728x90

인구 이동

문제

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.

오늘부터 인구 이동이 시작되는 날이다.

인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.

  • 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
  • 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
  • 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
  • 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
  • 연합을 해체하고, 모든 국경선을 닫는다.

각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.

 


설명

연결된 모든 인덱스를  방문하여 평균을 구해주는 문제.

 

처음 풀때 여기서 연결된? 이 부분을 이중 반복문을 이용해

map[i][j], map[i][j+1] 의 값 비교와

map[i][j], map[i+1][j] 의 값 비교를 하여 구하였는데 너무 복잡해져서

 

bfs를 이용하여 해결하였다. 방문하지 않았으면 방문하여 조건에 충족하는 모든 인덱스를 vector에 저장하여

move() 함수에서 해당 인덱스에 접근하여 계산해준다.

끝!


소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
#define MAX 50
using namespace std;
int n, l, r;
 
struct pos {
    int y, x;
};
 
int map[MAX][MAX];
bool visited[MAX][MAX];
int dx[] = { 1-100 };
int dy[] = { 001-1 };
vector<pos> v;
int ans, sum, cnt;
bool flag;
void move()
{
    int avg = sum / cnt;
    for (int i = 0; i < cnt; i++)
    {
        map[v[i].y][v[i].x] = avg;
    }
}
void bfs(int y, int x)
{
    queue<pos> q;
    q.push({ y,x });
    visited[y][x] = true;
    v.push_back({y,x});
    sum += map[y][x];
    cnt++;
    while (!q.empty())
    {
        int y = q.front().y;
        int x = q.front().x;
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            int ny = y + dy[i], nx = x + dx[i];
            if (ny >= 0 && nx >= 0 && ny < n && nx < n)
            {
                if (!visited[ny][nx])
                {
                    int temp = abs(map[y][x] - map[ny][nx]);
                    if (temp >= l && temp <= r)
                    {
                        q.push({ ny,nx });
                        visited[ny][nx] = true;
                        v.push_back({ ny,nx });
                        sum += map[ny][nx];
                        cnt++;
                    }
                }
            }
        }
    }
 
    if (v.size() > 1)
    {
        move();
        flag = true;
    }
    sum =0, cnt =0;
    v.clear();
}
int main()
{
    cin >> n >> l >> r;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cin >> map[i][j];
        }
    }
    while (true)
    {
        memset(visited, falsesizeof(visited));
        flag = false;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (!visited[i][j])
                {
                    bfs(i, j);
                }
            }
        }
        if (flag)ans++;
        else break;
    }
    cout << ans;
    return 0;
}
cs
LIST
728x90
 

문제

드래곤 커브는 다음과 같은 세 가지 속성으로 이루어져 있으며, 이차원 좌표 평면 위에서 정의된다. 좌표 평면의 x축은 → 방향, y축은 ↓ 방향이다.

  1. 시작 점
  2. 시작 방향
  3. 세대

0세대 드래곤 커브는 아래 그림과 같은 길이가 1인 선분이다. 아래 그림은 (0, 0)에서 시작하고, 시작 방향은 오른쪽인 0세대 드래곤 커브이다.

1세대 드래곤 커브는 0세대 드래곤 커브를 끝 점을 기준으로 시계 방향으로 90도 회전시킨 다음 0세대 드래곤 커브의 끝 점에 붙인 것이다. 끝 점이란 시작 점에서 선분을 타고 이동했을 때, 가장 먼 거리에 있는 점을 의미한다.

2세대 드래곤 커브도 1세대를 만든 방법을 이용해서 만들 수 있다. (파란색 선분은 새로 추가된 선분을 나타낸다)

3세대 드래곤 커브도 2세대 드래곤 커브를 이용해 만들 수 있다. 아래 그림은 3세대 드래곤 커브이다.

즉, K(K > 1)세대 드래곤 커브는 K-1세대 드래곤 커브를 끝 점을 기준으로 90도 시계 방향 회전 시킨 다음, 그것을 끝 점에 붙인 것이다.

크기가 100×100인 격자 위에 드래곤 커브가 N개 있다. 이때, 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래곤 커브의 일부인 정사각형의 개수를 구하는 프로그램을 작성하시오. 격자의 좌표는 (x, y)로 나타내며, 0 ≤ x ≤ 100, 0 ≤ y ≤ 100만 유효한 좌표이다.

입력

첫째 줄에 드래곤 커브의 개수 N(1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 드래곤 커브의 정보가 주어진다. 드래곤 커브의 정보는 네 정수 x, y, d, g로 이루어져 있다. x와 y는 드래곤 커브의 시작 점, d는 시작 방향, g는 세대이다. (0 ≤ x, y ≤ 100, 0 ≤ d ≤ 3, 0 ≤ g ≤ 10)

입력으로 주어지는 드래곤 커브는 격자 밖으로 벗어나지 않는다. 드래곤 커브는 서로 겹칠 수 있다.

방향은 0, 1, 2, 3 중 하나이고, 다음을 의미한다.

  • 0: x좌표가 증가하는 방향 (→)
  • 1: y좌표가 감소하는 방향 (↑)
  • 2: x좌표가 감소하는 방향 (←)
  • 3: y좌표가 증가하는 방향 (↓)

출력

첫째 줄에 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래곤 커브의 일부인 것의 개수를 출력한다.

예제 입력 1

3
3 3 0 1
4 2 1 3
4 2 2 1

예제 출력 1

4

예제 입력 2

4
3 3 0 1
4 2 1 3
4 2 2 1
2 7 3 4

예제 출력 2

11

예제 입력 3

10
5 5 0 0
5 6 0 0
5 7 0 0
5 8 0 0
5 9 0 0
6 5 0 0
6 6 0 0
6 7 0 0
6 8 0 0
6 9 0 0

예제 출력 3

8

예제 입력 4

4
50 50 0 10
50 50 1 10
50 50 2 10
50 50 3 10

예제 출력 4

1992

 

힌트


예제 1 예제 2
 

설명 

이런종류의 문제는 규칙을 찾아보자!

[ 0 = → , 1 = ↑ , 2 = ← , 3 = ↓ ]

세대       |   방향 정보

0               0

1               0  1

2               0  1  2  1

3               0  1  2  1  2  3  2  1

다음 세대의 추가되는 선분의 방향정보 = 이전 세대의 방향정보를 역순으로 탐색하면서 +1 % 4 를 한 것이 된다.

make_dragon_curve() 함수를 이용하여 map에 좌표를 찍어주고

count_square() 함수를 이용하여 좌표에 정사각형을 찾는다!

 

 

 


소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <vector>
#define MAX 101
using namespace std;
int n, x, y, g, d, ans;
vector<int> dir;
int map[MAX][MAX];
int dx[] = { 10-10 };
int dy[] = { 0-101 };
void make_dragon_curve()
{
    int size = dir.size();
    for (int i = size - 1; i >= 0; i--)
    {
        int next_d = (dir[i] + 1) % 4;
        x += dx[next_d];
        y += dy[next_d];
        map[y][x] = 1;
        dir.push_back(next_d);
    }
}
void count_square()
{
    for (int i = 0; i < MAX; i++)
    {
        for (int j = 0; j < MAX; j++)
        {
            if (map[i][j]==1 && map[i][j + 1== 1 && map[i + 1][j] == 1 && map[i + 1][j + 1]==1)
                ans++;
        }
    }
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> x >> y >> d >> g;
 
        dir.clear();
 
        map[y][x] = 1;
        x += dx[d];
        y += dy[d];
        map[y][x] = 1;
        dir.push_back(d);
        for (int j = 0; j < g; j++)
        {
            make_dragon_curve();
        }
    }
    count_square();
    cout << ans;
    return 0;
}
cs

https://yabmoons.tistory.com/60

 

[ 백준 15685 ] 드래곤 커브 (C++)

백준의 드래곤커브(15685) 문제이다. ( 문제 바로가기 ) 삼성의 SW역량테스트 기출문제이다. [ 문제풀이 ] 1. 그냥 문제를 보면 무슨소린지도 잘 모르겠고, 드래곤커브가 뭔지도 잘 모르겠다 사실.

yabmoons.tistory.com

참고하였습니다. 감사합니다.~

LIST
728x90

사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선이 같은 위치를 갖는다. 아래 그림은 N = 5, H = 6 인 경우의 그림이고, 가로선은 없다.

초록선은 세로선을 나타내고, 초록선과 점선이 교차하는 점은 가로선을 놓을 수 있는 점이다. 가로선은 인접한 두 세로선을 연결해야 한다. 단, 두 가로선이 연속하거나 서로 접하면 안 된다. 또, 가로선은 점선 위에 있어야 한다.

위의 그림에는 가로선이 총 5개 있다. 가로선은 위의 그림과 같이 인접한 두 세로선을 연결해야 하고, 가로선을 놓을 수 있는 위치를 연결해야 한다.

사다리 게임은 각각의 세로선마다 게임을 진행하고, 세로선의 가장 위에서부터 아래 방향으로 내려가야 한다. 이때, 가로선을 만나면 가로선을 이용해 옆 세로선으로 이동한 다음, 이동한 세로선에서 아래 방향으로 이동해야 한다.

위의 그림에서 1번은 3번으로, 2번은 2번으로, 3번은 5번으로, 4번은 1번으로, 5번은 4번으로 도착하게 된다. 아래 두 그림은 1번과 2번이 어떻게 이동했는지 나타내는 그림이다.

1번 세로선 2번 세로선

사다리에 가로선을 추가해서, 사다리 게임의 결과를 조작하려고 한다. 이때, i번 세로선의 결과가 i번이 나와야 한다. 그렇게 하기 위해서 추가해야 하는 가로선 개수의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 세로선의 개수 N, 가로선의 개수 M, 세로선마다 가로선을 놓을 수 있는 위치의 개수 H가 주어진다. (2 ≤ N ≤ 10, 1 ≤ H ≤ 30, 0 ≤ M ≤ (N-1)×H)

둘째 줄부터 M개의 줄에는 가로선의 정보가 한 줄에 하나씩 주어진다.

가로선의 정보는 두 정수 a과 b로 나타낸다. (1 ≤ a ≤ H, 1 ≤ b ≤ N-1) b번 세로선과 b+1번 세로선을 a번 점선 위치에서 연결했다는 의미이다.

가장 위에 있는 점선의 번호는 1번이고, 아래로 내려갈 때마다 1이 증가한다. 세로선은 가장 왼쪽에 있는 것의 번호가 1번이고, 오른쪽으로 갈 때마다 1이 증가한다.

입력으로 주어지는 가로선이 서로 연속하는 경우는 없다.

출력

i번 세로선의 결과가 i번이 나오도록 사다리 게임을 조작하려면, 추가해야 하는 가로선 개수의 최솟값을 출력한다. 만약, 정답이 3보다 큰 값이면 -1을 출력한다. 또, 불가능한 경우에도 -1을 출력한다.

 


문제 :  모든 라인이 자기자신의 번호에 도달하도록 추가 사다리의 최솟값 출력하는 문제!

 

깊이우선탐색을 이용하여 0개일 떄, 1개일때, 2개일때, 3개일때 모든 경우의 수를 찾되, 찾았으면 더이상 코드가 실행하지 않도록 처리 해준다.

 

추가 사다리를 놓을수 있는 경우는 놓고싶은 위치의 [해당 위치, 왼쪽, 오른쪽]에 가로 사다리가 없을 경우 가능하다

(lline 42)

 

이 문제에서는 배열의 범위 때문에 고생을 좀 했다. 

 

코드는 다른분의 코드를 참고하였는데 좀 오래되서 기억이안나는데... 아무튼 감사합니다.

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include<algorithm>
#define MAX 30
using namespace std;
 
int n, m, h;
int ladderCnt;
bool flag;
bool map[MAX][11];
 
void dfs(int y, int depth)
{
    if (flag)
        return;
    if (ladderCnt == depth)
    {
        bool possible = true;
        for (int i = 1; i <=n; i++)
        {
            int row = i;
            for (int j = 0; j < h; j++)
            {
                if (map[j][row])
                    row++;
                else if (row > 1 && map[j][row - 1])
                    row--;
            }
            if (i != row)
            {
                possible = false;
                break;
            }
        }
        if (possible)
            flag = true;
        return;
    }
    for (int i = y; i < h; i++)
    {
        for (int j = 1; j < n; j++)
        {
            if (!map[i][j - 1&& !map[i][j] && !map[i][j + 1])
            {
                map[i][j] = true;
                dfs(i, depth + 1);
                map[i][j] = false;
            }
        }
    }
    return;
}
int main()
{
    cin >> n >> m >> h;
    for (int i = 0; i < m; i++)
    {
        int y, x;
        cin >> y >> x;
        map[y - 1][x] = true;
    }
    for (int i = 0; i <= 3; i++)
    {
        ladderCnt = i;
        dfs(00);
        if (flag)
        {
            cout << ladderCnt;
            return 0;
        }
    }
    cout << -1;
    return 0;
}
cs
LIST
728x90

문제

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

1번 2번 3번 4번 5번

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 # 6 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
# # 1 0 6 0
0 0 0 0 0 0
0 0 # 0 0 0
0 0 # 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 # 0 0 0

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

0 0 0 0 0 #
# 2 # # # #
0 0 0 0 6 #
0 6 # # 2 #
0 0 0 0 0 #
# # # # # 5
0 0 0 0 0 #
# 2 # # # #
0 0 0 0 6 #
0 6 0 0 2 #
0 0 0 0 # #
# # # # # 5
0 # 0 0 0 #
0 2 0 0 0 #
0 # 0 0 6 #
0 6 # # 2 #
0 0 0 0 0 #
# # # # # 5
0 # 0 0 0 #
0 2 0 0 0 #
0 # 0 0 6 #
0 6 0 0 2 #
0 0 0 0 # #
# # # # # 5
왼쪽 상단 2: ↔, 오른쪽 하단 2: ↔ 왼쪽 상단 2: ↔, 오른쪽 하단 2: ↕ 왼쪽 상단 2: ↕, 오른쪽 하단 2: ↔ 왼쪽 상단 2: ↕, 오른쪽 하단 2: ↕

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

0 0 2 0 3
0 6 0 0 0
0 0 6 6 0
0 0 0 0 0

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

# # 2 # 3
0 6 # 0 #
0 0 6 6 #
0 0 0 0 #

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

출력

첫째 줄에 사각 지대의 최소 크기를 출력한다.


첫 번째 풀이 방법(시간 초과)

0. dfs() 호출

1. map[i][j]을 temp[i][j]에 복사

2. map[i][j] 변경

3. 조건 충족 후 temp[i][j]로 되돌리기.

이때 map[i][j] == 1,2,3,4,5 일 때 모두 배열의 복사, 되돌리기 진행,--> 시간 초과

 

두 번째 풀이 방법(정답)

0. dfs() 호출

1. 동서남북 네 가지 방향에 대한 반복문 안에서 감시범위 체크, dfs(), 다시 되돌리기 함수 실행

2. visited[][] 배열에 감시카메라가 닿는 모든 칸에 +1

3. dfs(depth + 1) 호출

4. visited[][] 배열에 감시카메라가 닿는 모든 칸에 -1

5. depth == (1~5)의 개수 일 때 visited[][]의 0의 개수 비교

*주의사항 dx dy를 시계방향, 반시계 방향 순서대로 정의해야 한다.

예를 들어 좌우상하라고 설정하면

2번 케이스일 때 (좌우)(우상)(상하)(하좌) 이런 식으로 방향이 틀려지게 된다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <vector>
#include <algorithm>
#define MAX 8
using namespace std;
int n, m;
int map[MAX][MAX], visited[MAX][MAX];
//하, 좌, 상, 우
int dx[] = { 0-101 };
int dy[] = { 10-10 };
struct pos {
    int y, x;
};
vector<pos> v;
int ans = 1e9;
void check(int y, int x, int dir, int num)
{
    int ny = y;
    int nx = x;
    while (true)
    {
        ny += dy[dir];
        nx += dx[dir];
        if (map[ny][nx] == 6)
            break;
        if (ny >= 0 && nx >= 0 && ny < n && nx < m)
            visited[ny][nx] += num;
        else
            break;
    }
}
void rotate(int depth, int i, int num)
{
    int y = v[depth].y;
    int x = v[depth].x;
    int number = map[y][x];
    switch (number)
    {
    case 1:
        check(y, x, (i + 3) % 4, num);
        break;
    case 2:
        check(y, x, (i + 1) % 4, num);
        check(y, x, (i + 3) % 4, num);
        break;
    case 3:
        check(y, x, (i + 2) % 4, num);
        check(y, x, (i + 3) % 4, num);
        break;
    case 4:
        check(y, x, (i + 1) % 4, num);
        check(y, x, (i + 2) % 4, num);
        check(y, x, (i + 3) % 4, num);
        break;
    case 5:
        check(y, x, (i + 0) % 4, num);
        check(y, x, (i + 1) % 4, num);
        check(y, x, (i + 2) % 4, num);
        check(y, x, (i + 3) % 4, num);
        break;
    }
}
void solve(int depth)
{
    if (depth == v.size())
    {
        int cnt = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (visited[i][j] == 0)
                    cnt++;
            }
        }
        ans = min(ans, cnt);
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        rotate(depth, i, 1);
        solve(depth + 1);
        rotate(depth, i, -1);
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> map[i][j];
            if (map[i][j] != 0 && map[i][j] != 6)
            {
                v.push_back({ i,j });
                visited[i][j] = map[i][j];
            }
            if (map[i][j] == 6)
                visited[i][j] = 6;
        }
    }
    solve(0);
    cout << ans;
    return 0;
}
cs

https://www.acmicpc.net/problem/15683

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net

 

LIST
728x90

톱니바퀴

문제

총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴가 1번, 그 오른쪽은 2번, 그 오른쪽은 3번, 가장 오른쪽 톱니바퀴는 4번이다.

이때, 톱니바퀴를 총 K번 회전시키려고 한다. 톱니바퀴의 회전은 한 칸을 기준으로 한다. 회전은 시계 방향과 반시계 방향이 있고, 아래 그림과 같이 회전한다.

톱니바퀴를 회전시키려면, 회전시킬 톱니바퀴와 회전시킬 방향을 결정해야 한다. 톱니바퀴가 회전할 때, 서로 맞닿은 극에 따라서 옆에 있는 톱니바퀴를 회전시킬 수도 있고, 회전시키지 않을 수도 있다. 톱니바퀴 A를 회전할 때, 그 옆에 있는 톱니바퀴 B와 서로 맞닿은 톱니의 극이 다르다면, B는 A가 회전한 방향과 반대방향으로 회전하게 된다. 예를 들어, 아래와 같은 경우를 살펴보자.

두 톱니바퀴의 맞닿은 부분은 초록색 점선으로 묶여있는 부분이다. 여기서, 3번 톱니바퀴를 반시계 방향으로 회전했다면, 4번 톱니바퀴는 시계 방향으로 회전하게 된다. 2번 톱니바퀴는 맞닿은 부분이 S극으로 서로 같기 때문에, 회전하지 않게 되고, 1번 톱니바퀴는 2번이 회전하지 않았기 때문에, 회전하지 않게 된다. 따라서, 아래 그림과 같은 모양을 만들게 된다.

위와 같은 상태에서 1번 톱니바퀴를 시계 방향으로 회전시키면, 2번 톱니바퀴가 반시계 방향으로 회전하게 되고, 2번이 회전하기 때문에, 3번도 동시에 시계 방향으로 회전하게 된다. 4번은 3번이 회전하지만, 맞닿은 극이 같기 때문에 회전하지 않는다. 따라서, 아래와 같은 상태가 된다.

톱니바퀴의 초기 상태와 톱니바퀴를 회전시킨 방법이 주어졌을 때, 최종 톱니바퀴의 상태를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 1번 톱니바퀴의 상태, 둘째 줄에 2번 톱니바퀴의 상태, 셋째 줄에 3번 톱니바퀴의 상태, 넷째 줄에 4번 톱니바퀴의 상태가 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터 시계방향 순서대로 주어진다. N극은 0, S극은 1로 나타나있다.

다섯째 줄에는 회전 횟수 K(1 ≤ K ≤ 100)가 주어진다. 다음 K개 줄에는 회전시킨 방법이 순서대로 주어진다. 각 방법은 두 개의 정수로 이루어져 있고, 첫 번째 정수는 회전시킨 톱니바퀴의 번호, 두 번째 정수는 방향이다. 방향이 1인 경우는 시계 방향이고, -1인 경우는 반시계 방향이다.

출력

총 K번 회전시킨 이후에 네 톱니바퀴의 점수의 합을 출력한다. 점수란 다음과 같이 계산한다.

  • 1번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 1점
  • 2번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 2점
  • 3번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 4점
  • 4번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 8점

문제가 겁나 기네... 그래도 그림이 많으니까 그림책 읽는거같다. ㅎㅎ

해결방법

입력된 톱니바퀴의 오른쪽 확인해서 turn[4] 값 업데이트!

왼쪽 확인해서 turn[4] 값 업데이트!

turn[4]의 값이 1 이면 오른쪽으로 회전! -1 이면 왼쪽으로 회전!

마지막으로 1~4톱니바퀴 0번째값 계산!

비교적 짧은 시간에 오류 없이 풀었지만 함수에서 string을 인자로 전달할때 디버깅해보니까 원래값으로 다시 돌아와서 

void turn_left(string& s) 로 수정해서 참조 전달로 수정해줬더니 정답처리 되었다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//BOJ-14891 톱니바퀴
#include <iostream>
#include <vector>
#define LEFT 6
#define RIGHT 2
using namespace std;
 
string s[4];
int turn[4], k, ans;
void turn_left(string& s)
{
    string tmp = s.substr(1, s.size()-1);
    tmp.push_back(s.at(0));
    s = tmp;
}
void turn_right(string& s)
{
    char tmp = s.at(s.size() - 1);
    string c;
    c += tmp;
    s.pop_back();
    s.insert(0, c);
}
int main()
{
    for (int i = 0; i < 4; i++)
    {
        cin >> s[i];
    }
    cin >> k;
    for (int i = 0; i < k; i++)
    {
        int a, b;
        cin >> a >> b;
        fill_n(turn, 40);
        turn[a - 1= b;
 
        int dir = b;
        //right
        for (int i = a; i < 4; i++)
        {
            if (s[i - 1][RIGHT] != s[i][LEFT])
            {
                if (dir == 1)
                {
                    turn[i] = -1;
                    dir = -1;
                }
                else
                {
                    turn[i] = 1;
                    dir = 1;
                }
            }
            else
            {
                break;
            }
        }
        dir = b;
        //left
        for (int i = a - 2; i >= 0; i--)
        {
            if (s[i + 1][LEFT] != s[i][RIGHT])
            {
                if (dir == 1)
                {
                    turn[i] = -1;
                    dir = -1;
                }
                else
                {
                    turn[i] = 1;
                    dir = 1;
                }
            }
            else
            {
                break;
            }
        }
 
        //turn
        for (int i = 0; i < 4; i++)
        {
            if (turn[i] == 1)
                turn_right(s[i]);
            else if (turn[i] == -1)
                turn_left(s[i]);
        }    
    }
    //calculate
    if (s[0][0== '1')
        ans += 1;
    if (s[1][0== '1')
        ans += 2;
    if (s[2][0== '1')
        ans += 4;
    if (s[3][0== '1')
        ans += 8;
    cout << ans;
    return 0;
}
cs

https://www.acmicpc.net/problem/14891

 

14891번: 톱니바퀴

총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴

www.acmicpc.net

 

LIST
728x90

로봇 청소기 

문제

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.

로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다. 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북중 하나이다. 지도의 각 칸은 (r, c)로 나타낼 수 있고, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로 부터 떨어진 칸의 개수이다.

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 위치를 청소한다.
  2. 현재 위치에서 현재 방향을 기준으로 왼쪽방향부터 차례대로 탐색을 진행한다.
    1. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
    2. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
    3. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
    4. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

로봇 청소기는 이미 청소되어있는 칸을 또 청소하지 않으며, 벽을 통과할 수 없다.

입력

첫째 줄에 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 50)

둘째 줄에 로봇 청소기가 있는 칸의 좌표 (r, c)와 바라보는 방향 d가 주어진다. d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우에는 서쪽을 바라보고 있는 것이다.

셋째 줄부터 N개의 줄에 장소의 상태가 북쪽부터 남쪽 순서대로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 빈 칸은 0, 벽은 1로 주어진다. 지도의 첫 행, 마지막 행, 첫 열, 마지막 열에 있는 모든 칸은 벽이다.

로봇 청소기가 있는 칸의 상태는 항상 빈 칸이다.

출력

로봇 청소기가 청소하는 칸의 개수를 출력한다.


이 문제에서 고려해야할 요소는 map[y][x] == 0 이면 출력 변수 ++ 해주고, 

다음 방향 탐색 -> 4방향 모두 막혀 있으면 뒤로 이동, 이때 뒤에가 벽이면 멈춘다.

그래서 for(int i=0;i< 4;i++){} 구문에 탐색하는 코드를 넣어 탐색에 실패했을경우 문제의 2.3에 해당하는지 2.4에 해당하는지 확인해 준다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* 로봇 청소기 영역의 개수를 구하는 프로그램 */
//n x m 영역 빈칸 or 벽
//방향 : 동 서 남 북
//로봇청소기 루틴
// 1. 현재 위치 청소
// 2. 현재위치에서 왼쪽방향부터 탐색
//   a. 왼쪽 방향이 청소하지 않았으면 그방향으로 전진 -> 1
//   b. 왼쪽 방향에 청소할 공간이 없으면, 그 방향 회전 -> 2
//   c. 네 방향 모두 청소가 이미 되어있거나 벽이면, 바라보는 방향 유지한 채로 후진 -> 2
//   d. 네 방향 모두 청소가 이미 되어있거나 벽이면서 뒤쪽방향도 벽이면 멈춤
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int n, m;
int input[50][50];
int y, x;
int ans;
int dir;
//북 동 남 서
int dx[] = { 010-1 };
int dy[] = { -1010 };
 
int left_dir(int d)
{
    if (d == 0)
    {
        return 3;
    }
    else if (d == 1)
    {
        return 0;
    }
    else if (d == 2)
    {
        return 1;
    }
    else
        return 2;
}
void solve()
{
    while (true)
    {
        if (input[y][x] == 0)
        {
            input[y][x] = 2;
            ans++;
        }
        bool nextClean = false;
        for (int i = 0; i < 4; i++)
        {
            dir = left_dir(dir);
            int ny = y + dy[dir];
            int nx = x + dx[dir];
 
            if (input[ny][nx] == 0)
            {
                x = nx;
                y = ny;
                nextClean = true;
                break;
            }
        }
        if (nextClean) continue;
        //뒤
        int back_d = left_dir(left_dir(dir));
        y = y + dy[back_d];
        x = x + dx[back_d];
 
        if (input[y][x] == 1)
            break;
    }
}
int main()
{
    cin >> n >> m;
 
    //입력 y, x, 바라보는 방향 d
    //d = 0 : 북 // d = 1 : 동 // d = 2 : 남 // d = 3 : 서
    cin >> y >> x >> dir;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> input[i][j];
        }
    }
    solve();
    cout << ans;
    return 0;
}
cs
LIST
728x90

퇴사 

https://www.acmicpc.net/problem/14501

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net

문제

상담원으로 일하고 있는 백준이는 퇴사를 하려고 한다.

오늘부터 N+1일째 되는 날 퇴사를 하기 위해서, 남은 N일 동안 최대한 많은 상담을 하려고 한다.

백준이는 비서에게 최대한 많은 상담을 잡으라고 부탁을 했고, 비서는 하루에 하나씩 서로 다른 사람의 상담을 잡아놓았다.

각각의 상담은 상담을 완료하는데 걸리는 기간 Ti와 상담을 했을 때 받을 수 있는 금액 Pi로 이루어져 있다.

N = 7인 경우에 다음과 같은 상담 일정표를 보자.

 1일2일3일4일5일6일7일TiPi

3 5 1 1 2 4 2
10 20 10 20 15 40 200

1일에 잡혀있는 상담은 총 3일이 걸리며, 상담했을 때 받을 수 있는 금액은 10이다. 5일에 잡혀있는 상담은 총 2일이 걸리며, 받을 수 있는 금액은 15이다.

상담을 하는데 필요한 기간은 1일보다 클 수 있기 때문에, 모든 상담을 할 수는 없다. 예를 들어서 1일에 상담을 하게 되면, 2일, 3일에 있는 상담은 할 수 없게 된다. 2일에 있는 상담을 하게 되면, 3, 4, 5, 6일에 잡혀있는 상담은 할 수 없다.

또한, N+1일째에는 회사에 없기 때문에, 6, 7일에 있는 상담을 할 수 없다.

퇴사 전에 할 수 있는 상담의 최대 이익은 1일, 4일, 5일에 있는 상담을 하는 것이며, 이때의 이익은 10+20+15=45이다.

상담을 적절히 했을 때, 백준이가 얻을 수 있는 최대 수익을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N (1 ≤ N ≤ 15)이 주어진다.

둘째 줄부터 N개의 줄에 Ti와 Pi가 공백으로 구분되어서 주어지며, 1일부터 N일까지 순서대로 주어진다. (1 ≤ Ti ≤ 5, 1 ≤ Pi ≤ 1,000)

출력

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.


이 문제를 읽고 나서 어디서 많이 봤는데... 하는 생각이 들어서 DP 문제를 몇문제 풀고 봤다.

오랜만에 DP로 풀려니까 머리가 너무 아프다.

그래서 얍문님의 블로그를 참고해서 DFS로 풀었다.

경우의 수를 두가지로 나누어

1. 해당 날을 상담하지않고, 다음날로 넘어가는 경우와

2. 해당 날을 상담하고, 해당 상담을 걸리는 일 수 만큼 건너 뛰어가는 경우를 고려하였다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
using namespace std;
int n;
int day[15];
int cost[15];
int ans;
//1. 해당 날의 상담을 하지 않고, 그 다음날로 넘어가는 방법
//2. 해당 날에 상담을 하고, 해당 상담을 하는데 걸리는 총 일수 만큼 넘어가는 방법
void dfs(int now_day, int total_cost)
{
    if (now_day >= n)
    {
        ans = max(ans, total_cost);
        return;
    }
    if (now_day + day[now_day] <= n)
        dfs(now_day + day[now_day], total_cost + cost[now_day]);
    if (now_day + 1 <= n)
        dfs(now_day + 1, total_cost);
 
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> day[i] >> cost[i];
    }
    dfs(00);
    cout << ans;
    return 0;
}
cs

참고

https://yabmoons.tistory.com/175

 

[ 백준 14501 ] 퇴사 (C++)

백준의 퇴사(14501) 문제이다. [ 문제 바로가기 ] 삼성전자 SW 역량테스트 기출문제이다.. [ 문제풀이 ] 1) 이 문제는 2가지 방법으로 풀 수가 있다. 먼저, Dynamic Programming으로 해결하는 방법이 있고,

yabmoons.tistory.com

 

LIST
728x90

테트로미노

https://www.acmicpc.net/problem/14500

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변

www.acmicpc.net

문제

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.

  • 정사각형은 서로 겹치면 안 된다.
  • 도형은 모두 연결되어 있어야 한다.
  • 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.

정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.

테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.

테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.

입력

첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)

둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.

출력

첫째 줄에 테트로미노가 놓인 칸에 쓰인 수들의 합의 최댓값을 출력한다.


문제를 처음 대충 읽었을때는 저위의 모양 5개를 이용해서 최댓값을 구하는 건 줄 알았는데

저 중에서 한개의 모양만을 이용해서 최대값을 구하는 문제였다.

그리고 저 모양을 대칭까지에 회전까지 해도 되니까 ㅗ,ㅓ,ㅜ,ㅏ 이 블록 빼고는 depth ==4 인 dfs 로 풀수 있다.

ㅗ,ㅓ,ㅜ,ㅏ 이 모양은 직접 좌표를 구현해서 결과를 테스트 하였다.

depth==4 인 dfs까지는 혼자 생각할 수 있었는데 ㅗ,ㅓ,ㅜ,ㅏ이 모양의 구현 방법은 잘 생각나지않아 다른 분들의 티스토리를 참고하였다. 끝.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <iostream>
#include <cstring>
#define MAX 501
using namespace std;
int ans, n, m;
int map[MAX][MAX];
bool visited[MAX][MAX];
int dx[] = { 1-100 };
int dy[] = { 00-11 };
//ㅗ
int get_Shape1(int y, int x)
{
    if (y > 1 && x > 1 && y < n-1 && x < m)
    {
        return map[y][x] + map[y][x - 1+ map[y][x + 1+ map[y - 1][x];
    }
    else
        return 0;
}
//ㅏ
int get_Shape2(int y, int x)
{
    if (y > 1 && x > 0 && y < n - 1 && x < m - 1)
    {
        return map[y][x] + map[y + 1][x] + map[y - 1][x] + map[y][x + 1];
    }
    else
        return 0;
}
//ㅓ
int get_Shape3(int y, int x)
{
    if (y > 1 && x > 1 && y < n - 1 && x < m)
    {
        return map[y][x] + map[y - 1][x] + map[y + 1][x] + map[y][x - 1];
    }
    else
        return 0;
}
//ㅜ
int get_Shape4(int y, int x)
{
    if (y > 0 && x > 1 && y < n - 1 && x < m - 1)
    {
        return map[y][x] + map[y][x - 1+ map[y][x + 1+ map[y + 1][x];
    }
    else
        return 0;
}
void findShape(int r, int c)
{
    // ㅜ 모양
    if (r + 1 < n && c + 2 < m)
    {
        ans = max(ans, map[r][c] + map[r][c + 1+ map[r][c + 2+ map[r + 1][c + 1]);
    }
    // ㅓ 모양
    if (r + 2 < n && c - 1 >= 0)
    {
        ans = max(ans, map[r][c] + map[r + 1][c] + map[r + 2][c] + map[r + 1][c - 1]);
    }
    // ㅗ 모양
    if (r - 1 >= 0 && c + 2 < m)
    {
        ans = max(ans, map[r][c] + map[r][c + 1+ map[r][c + 2+ map[r - 1][c + 1]);
    }
    // ㅏ 모양
    if (r + 2 < n && c + 1 < m)
    {
        ans = max(ans, map[r][c] + map[r + 1][c] + map[r + 2][c] + map[r + 1][c + 1]);
    }
}
void dfs(int y, int x, int depth, int cnt)
{
    if (depth == 3)
    {
        ans = max(ans, cnt);
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        int ny = y + dy[i]; int nx = x + dx[i];
        if (ny >= 0 && nx >= 0 && ny < n && nx < m)
        {
            if (!visited[ny][nx])
            {
                visited[ny][nx] = true;
                dfs(ny, nx, depth + 1, cnt + map[ny][nx]);
                visited[ny][nx] = false;
            }
        }
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> map[i][j];
        }
    }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            //memset(visited, 0, sizeof(visited));
            visited[i][j] = true;
            dfs(i, j, 0, map[i][j]);
            visited[i][j] = false;
            findShape(i, j);
        }
    }
    cout << ans;
    return 0;
}
cs
LIST

+ Recent posts