728x90

주사위 굴리기
www.acmicpc.net/problem/14499

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지도

www.acmicpc.net

문제

크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 이 지도의 위에 주사위가 하나 놓여져 있으며, 주사위의 전개도는 아래와 같다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 

2 4 1 3 5 6

주사위는 지도 위에 윗 면이 1이고, 동쪽을 바라보는 방향이 3인 상태로 놓여져 있으며, 놓여져 있는 곳의 좌표는 (x, y) 이다. 가장 처음에 주사위에는 모든 면에 0이 적혀져 있다.

지도의 각 칸에는 정수가 하나씩 쓰여져 있다. 주사위를 굴렸을 때, 이동한 칸에 쓰여 있는 수가 0이면, 주사위의 바닥면에 쓰여 있는 수가 칸에 복사된다. 0이 아닌 경우에는 칸에 쓰여 있는 수가 주사위의 바닥면으로 복사되며, 칸에 쓰여 있는 수는 0이 된다.

주사위를 놓은 곳의 좌표와 이동시키는 명령이 주어졌을 때, 주사위가 이동했을 때 마다 상단에 쓰여 있는 값을 구하는 프로그램을 작성하시오.

주사위는 지도의 바깥으로 이동시킬 수 없다. 만약 바깥으로 이동시키려고 하는 경우에는 해당 명령을 무시해야 하며, 출력도 하면 안 된다.

입력

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다.

둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 주사위를 놓은 칸에 쓰여 있는 수는 항상 0이다. 지도의 각 칸에 쓰여 있는 수는 10을 넘지 않는 자연수 또는 0이다.

마지막 줄에는 이동하는 명령이 순서대로 주어진다. 동쪽은 1, 서쪽은 2, 북쪽은 3, 남쪽은 4로 주어진다.

출력

이동할 때마다 주사위의 윗 면에 쓰여 있는 수를 출력한다. 만약 바깥으로 이동시키려고 하는 경우에는 해당 명령을 무시해야 하며, 출력도 하면 안 된다.


삼성SW역량테스트 기출문제 4번째 문제

주사위를 굴려서 주사위 값, 지도의 값을 갱신하는 문제

 

우선 주사위를 굴려서 나올 수 있는 경우의수를 보면

주사위는 6면으로 이루어져 있으므로

위의 방향 순서대로 아래와 같이 배열을 채웠을때

int dice[6] = {1, 2, 3, 4, 5, 6};

 

case 1:동쪽으로 굴리기

    dice = { dice[4], dice[2], dice[1], dice[6], dice[5], dice[3] };

case 2:서쪽으로 굴리기

    dice = { dice[3], dice[2], dice[6], dice[1], dice[5], dice[4] };

case 3:북쪽으로 굴리기

    dice = { dice[5], dice[1], dice[3], dice[4], dice[6], dice[2] };

case 4:남쪽으로 굴리기

    dice = { dice[2], dice[6], dice[3], dice[4], dice[1], dice[5] };

 

다음과 같이 변한다고 볼 수있다.

 

머리 좋은사람은 바로바로 계산이 되나??? 나는 직접 그림으로 그려서 경우의 수를 구했다.

아 그리고 이분의 코드를 따라해 보았습니다.

donggoolosori.github.io/2020/11/09/boj-14499/

 

[백준] 14499번 주사위 굴리기 - C++ - DGOS | 동꿀오소리

문제 14499번 주사위 굴리기 풀이 우선 주사위 각면의 숫자를 저장하는 크기 7의 dice 벡터를 만든다. 인덱스 번호를 맞추기 위해 크기를 7로 할당했다. 1 vector dice(7); // index 1 윗면, 2 북쪽면, 3

donggoolosori.github.io


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
#include <iostream>
#include <vector>
using namespace std;
int map[21][21];
int n, m, y, x, k;
int ans;
//index  1(동쪽) 2(서쪽) 3(북쪽) 4(남쪽)
//문제에 나와있는 순서대로
int dx[] = { 01-100 };
int dy[] = { 000-11 };
 
//움직임을 담는 배열
int moves[1001];
 
//위, 북, 동, 서, 남, 아래
vector<int> dice(7);
void move(int dir)
{
    //좌표움직임 설정한 순서대로
    switch (dir)
    {
        //동
    case 1:
        dice = { 0, dice[4], dice[2], dice[1], dice[6], dice[5], dice[3] };
        break;
        //서
    case 2:
        dice = { 0, dice[3], dice[2], dice[6], dice[1], dice[5], dice[4] };
        break;
        //북
    case 3:
        dice = { 0, dice[5], dice[1], dice[3], dice[4], dice[6], dice[2] };
        break;
        //남
    case 4:
        dice = { 0, dice[2], dice[6], dice[3], dice[4], dice[1], dice[5] };
        break;
    }
}
void solve()
{
    for (int i = 0; i < k; i++)
    {
        int ny = y + dy[moves[i]];
        int nx = x + dx[moves[i]];
        //범위를 벗어나는지 확인
        if (ny >= 0 && nx >= 0 && ny < n && nx < m)
        {
            //현재좌표 업데이트
            y = ny; x = nx;
            //움직인다.
            move(moves[i]);
            //주사위 윗면 출력
            cout << dice[1<< '\n';
            //지도가 0이면 지도에 주사위 아래 숫자 복사
            if (!map[y][x])
                map[y][x] = dice[6];
            //지도가 0이 아니면 주사위에 지도 숫자 복사, 지도 숫자-> 0
            else
            {
                dice[6= map[y][x];
                map[y][x] = 0;
            }
        }
    }
}
int main()
{
    cin >> n >> m >> y >> x >> k;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> map[i][j];
        }
    }
    for (int i = 0; i < k; i++)
        cin >> moves[i];
 
    solve();
    return 0;
}
cs

 

LIST
728x90

2048 (Easy) 

문제

2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.

이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)

입력

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.

출력

최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.


www.acmicpc.net/workbook/view/1152

 

문제집: 삼성 SW 역량 테스트 기출 문제 (baekjoon)

 

www.acmicpc.net

삼성 SW 역량 테스트 두번째 문제 2048(Easy)를 풀어보았다.

문제에서 5번 이동해서 구할수 있는 최댓값을 구하라고 되어있으므로 DFS 를 써야지 라는 생각은 바로 들었는데

그다음부터 어떻게 움직여야 최선일까? 라는 생각이 잘못됬다고 생각한다.

생각의 순서는 

1. DFS로 풀어야지.

2. 상하좌우 숫자를 어떻게 움직일까.

3. 배열을 어떤식으로 원상복구 해줄까.

다음의 세가지에 집중하면서 

jaimemin.tistory.com/660

 

백준 12100번 2048(Easy)

문제 링크입니다: https://www.acmicpc.net/problem/12100 핸드폰 게임인 2048을 모티브로 만든 문제이지만 게임과는 달리 한번 shift에서 이미 합체된 블록은 더 이상 합체되지 않는 점이 특징이였습니다.

jaimemin.tistory.com

이 분의 코드를 따라했다. 늘 느끼는거지만 코딩테스트 어렵다.. 나만 어렵나 오늘은 코드를 따로 올리지 않겠다.

90퍼센트 위의 코드랑 똑같다.

 


www.acmicpc.net/problem/12100

 

12100번: 2048 (Easy)

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

www.acmicpc.net

 

LIST
728x90

최소 스패닝 트리

문제

그래프가 주어졌을 때, 그 그래프의 최소 스패닝 트리를 구하는 프로그램을 작성하시오.

최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다.

입력

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이 가중치 C인 간선으로 연결되어 있다는 의미이다. C는 음수일 수도 있으며, 절댓값이 1,000,000을 넘지 않는다.

그래프의 정점은 1번부터 V번까지 번호가 매겨져 있고, 임의의 두 정점 사이에 경로가 있다. 최소 스패닝 트리의 가중치가 -2,147,483,648보다 크거나 같고, 2,147,483,647보다 작거나 같은 데이터만 입력으로 주어진다.

출력

첫째 줄에 최소 스패닝 트리의 가중치를 출력한다.

 


 

개념 : 방향없는 그래프에서 모든 노드를 포함하면서, 순환되는 경로를 제거한 현태를 스패닝 트리(Spanning Tree) 라고 한다. 이 스패일 트리에서 가중치의 합을 최소로 만드는 스패닝 트리를 최소 스패닝트리(Minimal Spanning Tree)라고 한다. 최소 스패닝 트리를 만들기 위한 방법으로는 크루스칼 알고리즘을 이용한다!

 

크루스칼 알고리즘에 대해서는 한빛미디어 - 이것이코딩테스트다 with python 을 참고하시길 바랍니다.

www.youtube.com/watch?v=Gj7s-Nrt1xE&list=PLVsNizTWUw7H9_of5YCB0FmsSc-K44y81&index=35&ab_channel=%ED%95%9C%EB%B9%9B%EB%AF%B8%EB%94%94%EC%96%B4

unionParent, findParent는 여러 알고리즘을 풀면서 종종 이용해 먹을만한 개념이라고 생각한다.


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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, m;
 
int parent[10001];
int ans;
struct node {
    int val, x, y;
    node(int val, int x, int y)
    {
        this->val = val;
        this->= x;
        this->= y;
    }
};
vector<node> v;
int findParent(int x)
{
    if (x == parent[x]) return x;
    else return parent[x] = findParent(parent[x]);
}
 
bool sameParent(int x, int y)
{
    x = findParent(x);
    y = findParent(y);
    if (x == y)return true;
    else return false;
}
 
void unionParent(int x, int y)
{
    x = findParent(x);
    y = findParent(y);
    if (x > y) parent[x] = y;
    else parent[y] = x;
}
bool compare(node& a, node& b)
{
    return a.val < b.val;
}
int main()
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        v.push_back(node( c,a,b ));
    } 
    sort(v.begin(), v.end(), compare);
    for (int i = 0; i < n; i++)
        parent[i] = i;
 
    for (int i = 0; i < v.size(); i++)
    {
        if (!sameParent(v[i].x, v[i].y))
        {
            unionParent(v[i].x, v[i].y);
            ans += v[i].val;
        }
    }
    cout << ans;
    
    return 0;
}
cs
LIST
728x90

부분수열의 합

문제

N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.

출력

첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.


이번문제는 백트레킹! 부분수열의 합 입니다.

n개의 원소중에서 m개를 뽑았을때 합이 S 이면 결과값을 늘려나가는 방법을 이용했습니다.

여기서 m개의 범위는 1 <= m <=n 으로 하였습니다.

기본적으로 nCm (1<=m<=n) 일때 결과값이 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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n, m;
int a[20];
vector<int> v;
int check[20];
int ans;
void dfs(int depth, int next, int k)
{
    if (depth == k)
    {
        int sum = 0;
        for (int i = 0; i < n; i++)
            sum += a[i];
        if (sum == m) ans++;
 
        return;
    }
    for (int i = next; i < n; i++)
    {
        if (!check[i])
        {
            check[i] = true;
            a[depth] = v[i];
            dfs(depth + 1, i + 1, k);
            check[i] = false;
        }
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        int k;
        cin >> k;
        v.push_back(k);
    }
    for(int i=1;i<=n;i++)
        dfs(00, i);
    cout << ans;
    return 0;
}
cs
LIST
728x90

로또

문제

독일 로또는 {1, 2, ..., 49}에서 수 6개를 고른다.

로또 번호를 선택하는데 사용되는 가장 유명한 전략은 49가지 수 중 k(k>6)개의 수를 골라 집합 S를 만든 다음 그 수만 가지고 번호를 선택하는 것이다.

예를 들어, k=8, S={1,2,3,5,8,13,21,34}인 경우 이 집합 S에서 수를 고를 수 있는 경우의 수는 총 28가지이다. ([1,2,3,5,8,13], [1,2,3,5,8,21], [1,2,3,5,8,34], [1,2,3,5,13,21], ..., [3,5,8,13,21,34])

집합 S와 k가 주어졌을 때, 수를 고르는 모든 방법을 구하는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있다. 첫 번째 수는 k (6 < k < 13)이고, 다음 k개 수는 집합 S에 포함되는 수이다. S의 원소는 오름차순으로 주어진다.

입력의 마지막 줄에는 0이 하나 주어진다. 

출력

각 테스트 케이스마다 수를 고르는 모든 방법을 출력한다. 이때, 사전 순으로 출력한다.

각 테스트 케이스 사이에는 빈 줄을 하나 출력한다.



이번 문제는 조합의 응용 문제인 로또 문제를 풀어 보겠습니다.

 

이전 n과m(2)에서의 입력 조건은 N 이 주어 졌을때 1, 2, 3, .... N 이 범위라면

이번에는 n의 범위를 직접 입력해서 6개를 중복 없이 뽑는 경우의 수 입니다.

 

* 0이 입력될때까지 무한 반복

* while 실행시 사용했던 배열 초기화가 이루어져야 합니다.


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
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n;
vector<int> v;
int a[49];
int check[49];
void combination(int depth, int next)
{
    if (depth == 6)
    {
        for (int i = 0; i < 6; i++)
        {
            cout << a[i] << ' ';
        }
        cout << '\n';
        return;
    }
    for (int i = next; i < n; i++)
    {
        if (!check[i])
        {
            check[i] = true;
            a[depth] = v[i];
            combination(depth + 1, i + 1);
            check[i] = false;
        }
    }
}
int main()
{
    while (true)
    {
        cin >> n;
        if (n == 0break;
        v.clear();
        fill(check, check + 490);
        fill(a, a + 490);
        for (int i = 0; i < n; i++)
        {
            int a;
            cin >> a;
            v.push_back(a);
        }
        sort(v.begin(), v.end());
        combination(00);
        cout << '\n';
    }
    return 0;
}
cs

 

LIST

+ Recent posts