<백트래킹 + 이분매칭>으로 해결했다.


숫자가 1이상인 검은칸을 발견하면 vector<point>에 push_back 해주면서 map을 N-Rook을 풀 때 처럼 horizontal, vertical을 mapping해준다.


숫자가 0인 경우는 -1000으로 만들어 줘서 백트래킹 도중에 생기는 0인 칸과 헷갈리지 않도록 한다.


그 후 전구가 올 수 있는 곳에서 간선을 연결해주고 숫자가 1 이상인 검은칸에 대해서 백트래킹을 한다.


백트래킹은 상하좌우중 놓을 수 있는 곳이 있다면 그곳에 전구를 놓고 그 전구의 상하좌우의 숫자 1 이상인 검은 칸에 대해서 -=1 해준다.


당연히 전구를 놓는 곳 주변에 0인 칸이 있다면 불가능한 곳으로 인식한 후 다음 방향을 검색한다. dfs(x)의 x는 x번째 point를 뜻한다.


x==vector<point>.size()라면 true를 리턴한다. 전구를 놓을 때 당연히 horizontal, vertical을 체크한다. 그렇게 모두 배치한 다음 이분매칭을 진행한다.


이분매칭을 진행할 때 x와 pf[x]는 간선에 대한 정보일 뿐 좌표에 대한 정보가 아니므로 간선을 g에 추가할 때 좌표도 같이 추가해 주니 편했다.



ps. 코드 정말 더럽게 짜버렸다... 깔끔하게 만들어보고 싶다. 그리고 더 좋은 방법이 있을 것 같은데 생각이 나질 않는다.



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
#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
 
struct p {
    int x, y;
    p(int x, int y) : x(x), y(y) {}
    p operator+(const p &a) { return p(x + a.x, y + a.y); }
};
 
int t, n, map[7][7], h[7][7], v[7][7], dx[] = { 0,0,1,-1 }, dy[] = { 1,-1,0,0 }, res[7][7], pf[30];
bool c[30], hc[30], vc[30];
vector<pair<int, p>> g[30];
vector<p> sp;
 
bool check(int x, int y) {
    return x < 0 || y < 0 || x >= n || y >= n;
}
 
// x,y에 놓는게 불가능하다고 판단된 경우 되돌리기
void erase(int x, int y) {
    hc[h[x][y]] = vc[v[x][y]] = false;
    map[x][y] = -2;
    for (int j = 0; j < 4; j++) {
        int nx = x + dx[j], ny = y + dy[j];
        if (check(nx, ny) || map[nx][ny] < 0continue;
        map[nx][ny]++;
    }
}
 
bool dfs(int x) {
    if (x == sp.size()) return true;
    p cur = sp[x];
    if (map[cur.x][cur.y] <= -1000 || map[cur.x][cur.y] == 0return dfs(x + 1);
    else {
        for (int i = 0; i < 4; i++) {
            p nx = cur + p(dx[i], dy[i]);
            if (check(nx.x, nx.y) || map[nx.x][nx.y] != -2 || hc[h[nx.x][nx.y]] || vc[v[nx.x][nx.y]]) continue;
            bool f = true;
            for (int j = 0; j < 4 && f; j++) {
                p nnx = nx + p(dx[j], dy[j]);
                if (check(nnx.x, nnx.y)) continue;
                if (map[nnx.x][nnx.y] == 0 || map[nnx.x][nnx.y] == -1000) f = false;
            }
            if (f) {
                map[nx.x][nx.y] = -200;
                for (int j = 0; j < 4; j++) {
                    p nnx = nx + p(dx[j], dy[j]);
                    if (check(nnx.x, nnx.y) || map[nnx.x][nnx.y] <= 0continue;
                    map[nnx.x][nnx.y]--;
                }
                hc[h[nx.x][nx.y]] = vc[v[nx.x][nx.y]] = true;
                // cur옆에 더 둘 수 있으면 x, 아니면 다음순서인 x+1
                if (dfs(x + (map[cur.x][cur.y] ? 0 : 1))) return true
                else erase(nx.x, nx.y);
            }
        }
    }
    return false;
}
 
int dfs2(int x) {
    if (x == -1return 1;
    for (auto i : g[x]) {
        if (vc[i.first]|| c[i.first]) continue;
        bool f = false;
        for (int j = 0; j < 4; j++) {
            int nx = i.second.x + dx[j], ny = i.second.y + dy[j];
            if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
            if (map[nx][ny] == 0 || map[nx][ny] == -1000) {
                f = true;
                break;
            }
        }
        if (f) continue;
        c[i.first] = 1;
        if (dfs2(pf[i.first])) {
            pf[i.first] = x;
            return 1;
        }
    }
    return 0;
}
 
void init() {
    memset(h, -1sizeof(h));
    memset(v, -1sizeof(v));
    memset(hc, falsesizeof(hc));
    memset(vc, falsesizeof(vc));
    memset(res, 0sizeof(res));
    memset(pf, -1sizeof(pf));
    sp.clear();
    for (int i = 0; i < 30; i++) g[i].clear();
}
 
int main() {
    for (scanf("%d"&t); t--;) {
        init();
        scanf("%d"&n);
        int cnt = 0, cnt2 = 0, i, j;
        for (i = 0; i < n; i++for (j = 0; j < n; j++scanf("%d"&map[i][j]);
        // mapping
        for (i = 0; i < n; i++) {
            bool f1 = false, f2 = false;
            for (j = 0; j < n; j++) {
                if (map[i][j] == -2) h[i][j] = cnt, f1 = true;
                if (map[j][i] == -2) v[j][i] = cnt2, f2 = true;
                if (f1 && map[i][j] >= -1) cnt++, f1 = false;
                if (f2 && map[j][i] >= -1) cnt2++, f2 = false;
                if (map[i][j] > 0) sp.push_back({ i,j });
                else if (!map[i][j]) map[i][j] = -1000;
            }
            if (f1) cnt++, f1 = false;
            if (f2) cnt2++, f2 = false;
        }
        // edge 이어주기
        for (i = 0; i < n; i++for (j = 0; j < n; j++if (map[i][j] == -2
            g[h[i][j]].push_back({ v[i][j],{i,j} });
 
        dfs(0);
        for (int i = 0; i < 30; i++) {
            if (hc[i]) continue;
            memset(c, falsesizeof(c));
            dfs2(i);
        }
 
        for (i = 0; i < n; i++for (j = 0; j < n; j++
            if (map[i][j] == -200) res[i][j] = 1;
        for (i = 0; i < 30; i++) {
            if (pf[i] == -1continue;
            for (j = 0; j < g[pf[i]].size(); j++if (g[pf[i]][j].first == i) {
                res[g[pf[i]][j].second.x][g[pf[i]][j].second.y] = 1;
                break;
            }
        }
        for (i = 0; i < n; i++printf("\n")) for (j = 0; j < n; j++
            printf("%d ", res[i][j]);
    }
    return 0;
}
cs


'BOJ' 카테고리의 다른 글

1987 알파벳  (0) 2017.10.03
1269 대칭 차집합  (0) 2017.10.03
3187 양치기 꿍  (0) 2017.09.12
3640 제독  (0) 2017.09.07
3056 007  (0) 2017.09.06

+ Recent posts