백준 14391 종이 조각
본문 바로가기
알고리즘 모음집/알고리즘 (Algorithm)

백준 14391 종이 조각

by KyeongMin 2019. 7. 21.
728x90
반응형

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

 

14391번: 종이 조각

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고, 열은 왼쪽부터 오른쪽까지 번호가 매겨져 있다. 영선이는 직사각형을 겹치지 않는 조각으로 자르려고 한다. 각 조각은 크기가 세로나 가로 크기가 1인 직사각형 모양이다. 길이가 N인 조각은 N자리 수로 나타낼 수 있다. 가로 조각은 왼쪽부터 오른쪽까지 수를 이어 붙인

www.acmicpc.net

이전에 https://3dpit.tistory.com/11?category=791949

 

백준 17136 색종이 붙이기

https://www.acmicpc.net/problem/17136 17136번: 색종이 붙이기 <그림 1>과 같이 정사각형 모양을 한 다섯 종류의 색종이가 있다. 색종이의 크기는 1×1, 2×2, 3×3, 4×4, 5×5로 총..

3dpit.tistory.com

색종이 붙이기를 리뷰 하면서 다음에는 종이 조각에 대해서 말씀드리겠다 했던 문제입니다.

이전에 색종이 붙이기를 못 보신 분들은 먼저 색종이 붙이기 보시고 이번장에 들어오셔도 괜찮습니다.

아니더라도 종이 조각하시고 색종이 붙이기 하셔도 괜찮습니다. 

우선 종이 조각은 입력으로 주어지는 정사각형에 숫자가 들어있는데 

위의 7개의 도형을 이용해 전체를 나누었을때 나눈 구역의 숫자의 합이 최대가 되는것을 출력하는 문제입니다.

지금까지 같이 풀어오신분들은 이문제도 백트래킹으로 하면 되겠구나 바로 감이 오실것입니다.

맞습니다. 이문제도 백트래킹을 이용해서 풀수 있습니다.

여기서 포인트는 위의 7개의 도형을 전체 덮고 각 구역을 숫자로 만들어 더해서 최대값을 뽑을수 있는 소스를 구현할수 있는가 입니다. 

 

저의 풀이 방식을 간단히 설명해드리자면 백트래킹을 하는 기본적인 틀에 

재귀로 들어가기전에 배열을 복사를 해놓고 체크 배열에 각 7개에 맞는 도형의 숫자를

입력을 하고 체크배열이 가득찬경우에 각 구역을 숫자로 만들어 더한후 최대값 비교를

진행을 하였습니다.

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include<stdio.h>
int N, M;
int map[5][5];
int mmap[5][5];
int paper[10];
int num[10];
int ten[10= { 0,1,10,100,1000,10000 };
int chk[5][5];
int paper_idx[10][3= {
    {0,0},
    {1,1},
    {1,2},
    {2,1},
    {1,3},
    {3,1},
    {1,4},
    {4,1}
};
int idx1 = 0;
int max = 0x80000000;
void copy(int cmap[5][5], int map[5][5]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cmap[i][j] = map[i][j];
        }
    }
}
struct Data {
    int y; int x;
};
int ret = 0;
int check(int y, int x, int idx) {
    int maxnum = 0x80000000;
    maxnum = paper_idx[idx][0> paper_idx[idx][1] ? paper_idx[idx][0] : paper_idx[idx][1];
    for (int i = y; i < y + paper_idx[idx][0]; i++) {
        for (int j = x; j < x + paper_idx[idx][1]; j++) {
            if (i > N - 1 || j > M - 1 || map[i][j] == 99)return 0;
 
        }
    }
    return 1;
}
void dfs(int y, int x, int idx) {
 
    
    int flag = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (map[i][j] != 99) {
                flag = 1;
                break;
            }
        }
        if (flag)break;
    }
    if (flag == 0) {
        //for (int i = 0; i < N; i++) {
        //    for (int j = 0; j < M; j++) { 
        //        printf("%2d", chk[i][j]);
        //    }
        //    printf("\n");
        //}
        //printf("\n");
 
        ret = 0;
        int c[5][5= { 0, };
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (c[i][j] == 0) {
                    c[i][j] = 1;
                    int maxnum = paper_idx[chk[i][j]][0> paper_idx[chk[i][j]][1] ? paper_idx[chk[i][j]][0] : paper_idx[chk[i][j]][1];
 
                    for (int ii = i; ii < i + paper_idx[chk[i][j]][0]; ii++) {
                        for (int jj = j; jj < j + paper_idx[chk[i][j]][1]; jj++) {
                            ret += mmap[ii][jj] * ten[maxnum];
                            c[ii][jj] = 1;
                            maxnum--;
                        }
                    }
                }
            }
        }
        if (max < ret)max = ret;
        return;
    }
    if (idx != 0) {
        if (check(y, x, idx) == 1) {
            for (int i = y; i < y + paper_idx[idx][0]; i++) {
                for (int j = x; j < x + paper_idx[idx][1]; j++) {
                    map[i][j] = 99;
                    chk[i][j] = idx;
                }
            }
        }
        else return;
    }
    int flag1 = 0;
    int i; int j;
    for (i = 0; i < N; i++) {
        for (j = 0; j < M; j++) {
            if (map[i][j] != 99) {
                flag1 = 1;
                break;
            }
        }
        if (flag1)break;
    }
 
    int cmap[5][5= { 0, };
    int cchk[5][5= { 0, };
    for (int nn = 1; nn <= 7; nn++) {
        if (num[nn] == N*M) continue;
        //if (check(i, j, idx) == 1) {
            copy(cmap, map);
            copy(cchk, chk);
 
            num[nn]++;
 
            dfs(i, j, nn);
            num[nn]--;
 
            copy(map, cmap);
            copy(chk, cchk);
        }
 
    //}
}
int main(void)
{
    scanf("%d %d"&N, &M);
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            scanf("%1d"&map[i][j]);
            mmap[i][j] = map[i][j];
        }
    }
    dfs(000);
    printf("%d\n", max);
    return 0;
}
 
 

처음에  각 도형을 쓸수 있는 최대 갯수를 4 X 4기준으로 잡아 시간초과가 났었는데

입력으로 들어오는 N * M 만큼의 갯수를 최대로 잡아 시간 초과를 해결할수 있었습니다.

항상 백트래킹을 할때는 가지치기도 잘해야하고 몇개를쓰는지 잘정해야 한번에 

통과 할 수 있으니 항상 신경쓰고 구현하도록 합시다.

728x90
반응형

댓글