기술 블로그

17075번 유물 복원 본문

알고리즘 문제/BOJ

17075번 유물 복원

parkit 2020. 3. 9. 01:13
728x90
반응형

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


왜 0ms인지 질문 : https://www.acmicpc.net/board/view/48091



dp 메모이제이션 캐시 cache 복습 코테 필수 추천 냅색 boj 백준



2019 연세대학교 컴퓨터과학과 프로그래밍 경진대회 D번


한 점에 대해서 모든 경우의 수들을 탐색.


t 2차원 배열은 -1인 곳에서 얼마만큼 사용을 했는지 "사용 횟수"로 접근했었다.


그러나 시간이 900ms가 넘었다.


정답자 분들 중 코드를 참고하였더니, 공식같은 것이 있었다.


사실 공식은 아니지만 조금만 더 생각해보면 접근할 수 있었던 식이다.


나는 그냥 아무 생각없이 for문 돌리면 되겠다 싶어 다른 방법은 생각하지 않았다.



해당 좌표(i, j)를 포함하는 나올 수 있는 모든 직사각형의 호출 횟수는 가로의 길이 = C, 세로의 길이 = R이라고 할 때,


(i + 1) * (j + 1) * (R - i) * (C - j)


이다.






시간이 무려 900ms가 넘는 코드


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
#include <bits/stdc++.h>
 
using namespace std;
 
#define Max 52
 
int R, C, K, m[Max][Max], t[Max][Max], sum;
bool use[Max][Max];
 
// (sr, sc) ~ (er, ec) '1'인 곳의 합
int calc(int sr, int sc, int er, int ec)
{
    int ret = 0;
 
    for (int i = sr; i <= er; i++) {
        for (int j = sc; j <= ec; j++) {
            if (m[i][j] == -1) {
                ++t[i][j]; // -1은 따로 t 2차원 배열에 그 횟수를 1 증가시킨다.
            }
            else {
                ret += m[i][j];
            }
        }
    }
 
    return ret;
}
 
// 한 점(r, c)을 기준으로 그 점에 대해서 모든 직사각형 안에 있는 1의 합을 구한다.
int simulation(int r, int c)
{
    int ret = 0;
 
    for (int i = r; i < R; i++) {
        for (int j = c; j < C; j++) {
            ret += calc(r, c, i, j);
        }
    }
 
    return ret;
}
 
// 정답 출력(K의 배수인지 검사)
void chk(int s)
{
    if ((sum + s) % K == 0) {
        printf("1\n");
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (m[i][j] == -1) {
                    printf("%d ", use[i][j] ? 1 : 0);
                }
                else {
                    printf("%d ", m[i][j]);
                }
            }
            printf("\n");
        }
        exit(0);
    }
}
 
// 백트래킹
void dfs(int r, int c, int s)
{    
    // K의 배수가 되는지 검사
    chk(s);
 
    if (c == C) {
        c = 0;
        ++r;
    }
 
    if (r == R) {
        return;
    }
 
    if (m[r][c] == -1) {
        use[r][c] = true;
        dfs(r, c + 1, s + t[r][c]);
        use[r][c] = false;
    }
 
    // 해당 칸(r, c)을 선택(덧셈)을 안 할 때
    dfs(r, c + 1, s);
}
 
int main()
{
    cin.tie(0);
 
    scanf("%d %d %d"&R, &C, &K);
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            scanf("%d"&m[i][j]);
        }
    }
 
    // 나올 수 있는 모든 직사각형에서 1의 합(단, -1인 곳은 t 배열에 그 횟수를 저장하였음)
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            sum += simulation(i, j);
        }
    }
 
    // 백트래킹
    dfs(000);
 
    printf("-1\n");
 
    return 0;
}
cs








0ms 코드

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
#include <bits/stdc++.h>
 
using namespace std;
 
#define Max 52
 
int R, C, K, m[Max][Max], t[Max][Max], sum;
bool use[Max][Max];
 
// 정답 출력(K의 배수인지 검사)
void chk(int s)
{
    if ((sum + s) % K == 0) {
 
        printf("1\n");
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (m[i][j] == -1) {
                    printf("%d ", use[i][j] ? 1 : 0);
                }
                else {
                    printf("%d ", m[i][j]);
                }
            }
            printf("\n");
        }
 
        exit(0); // 바로 종료
    }
}
 
// 백트래킹
void dfs(int r, int c, int s)
{    
    // K의 배수가 되는지 검사
    chk(s);
 
    if (c == C) {
        c = 0;
        ++r;
    }
 
    if (r == R) {
        return;
    }
 
    if (m[r][c] == -1 && !use[r][c]) {
        use[r][c] = true;
        dfs(r, c + 1, s + t[r][c]);
        use[r][c] = false;
    }
 
    // 해당 칸(r, c)을 선택(덧셈) 안 할 때
    dfs(r, c + 1, s);
}
 
int main()
{
    cin.tie(0);
 
    scanf("%d %d %d"&R, &C, &K);
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            scanf("%d"&m[i][j]);
            if (m[i][j] == 1) {
                sum += (i + 1)*(R - i)*(j + 1)*(C - j); // 공식
            }
            else if (m[i][j] == -1) {
                t[i][j] += (i + 1)*(R - i)*(j + 1)*(C - j); // 공식
            }
        }
    }
 
    // 백트래킹
    dfs(000);
 
    printf("-1\n");
 
    return 0;
}
cs








728x90
반응형

'알고리즘 문제 > BOJ' 카테고리의 다른 글

1826번 연료 채우기  (0) 2020.03.10
16920번 확장 게임  (0) 2020.03.10
13302번 리조트  (0) 2020.03.08
10158번 개미  (0) 2020.03.07
11266번 단절점  (0) 2020.03.06