문제: icpc.me/12922
1x1x2 블럭이 정사각형 그리드에서 이동할 때 게임승리를 불가능하게 뚫어야하는 구멍의 수를 출력하는 문제이다.
문제에서 블럭의 이동경로를 살펴보면 시작점에서 부터 4방향으로 3칸 떨어진 지점에만 서있을 수 있다.
이를 이용하여 모든 정점에서 3칸 떨어진 지점으로 그래프를 구성해주는데 이 때 간선의 capacity는 지나가는 경로에 뚫어야하는 구멍 수가 되야되고 해당 정점에 구멍을 뚫는 경우는 정점을 분할하여 사이에 capacity를 1로 주는걸로 그래프를 모델링 해주면
src에서 sink로의 mincut을 구해주면 답을 구해낼 수 있다.
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 | #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <queue> #define INF 987654321 using namespace std; struct dinic { int n; struct Edge { int v, cap, rev; Edge(int v, int cap, int rev) :v(v), cap(cap), rev(rev) {} }; vector<vector<Edge>> vt; vector<int> level, work; dinic(int n) : n(n) { vt.resize(n + 1); } void addEdge(int s, int e, int c) { vt[s].emplace_back(e, c, vt[e].size()); vt[e].emplace_back(s, 0, vt[s].size() - 1); } bool bfs(int src, int sink) { queue<int> qu; level.assign(n + 1, -1); level[src] = 0; qu.push(src); while (qu.size()) { int here = qu.front(); qu.pop(); for (auto next : vt[here]) { if (next.cap&&level[next.v] == -1) { level[next.v] = level[here] + 1; qu.push(next.v); } } } return level[sink] != -1; } int dfs(int here, int crtcap, int target) { if (here == target)return crtcap; for (int &i = work[here]; i < vt[here].size(); i++) { int next = vt[here][i].v; int cap = vt[here][i].cap; if (cap&&level[here] + 1 == level[next]) { int flow = dfs(next, min(cap, crtcap), target); if (flow) { vt[here][i].cap -= flow; vt[next][vt[here][i].rev].cap += flow; return flow; } } } return 0; } int stream(int src, int sink) { int ret = 0; while (bfs(src, sink)) { work.assign(n + 1, 0); while (1) { int flow = dfs(src, INF, sink); if (!flow)break; ret += flow; } } return ret; } }; int n; int dx[] = { 0,0,1,-1 }; int dy[] = { 1,-1,0,0 }; int chk(int x, int y) { return 0 <= x&&x < n && 0 <= y&&y < n; } char a[55][55]; int main() { scanf("%d", &n); dinic f(2 * n*n + 3); for (int i = 0; i < n; i++) scanf("%s", a[i]); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (a[i][j] == 'H')continue; else if (a[i][j] == 'b') f.addEdge(2 * n*n + 1, i*n + j, INF); else if (a[i][j] == '$') { f.addEdge(n*n + i*n + j, 2 * n*n + 2, INF); for (int k = 0; k < 4; k++) { int tx = i + 3 * dx[k]; int ty = j + 3 * dy[k]; if (chk(tx, ty)) { int cap = (a[i + dx[k]][j + dy[k]] == 'b' ? 1 : 0) + (a[i + 2 * dx[k]][j + 2 * dy[k]] == 'b' ? 1 : 0); if (a[tx][ty] == 'b'&&cap) { puts("-1"); return 0; } } } } if (a[i][j] == '.') f.addEdge(i*n + j, n*n + i*n + j, 1); else f.addEdge(i*n + j, n*n + i*n + j, INF); for (int k = 0; k < 4; k++) { int tx = i + 3 * dx[k]; int ty = j + 3 * dy[k]; if (chk(tx, ty) && a[tx][ty] != 'H') { int cap = (a[i + dx[k]][j + dy[k]] == '.' ? 1 : 0) + (a[i + 2 * dx[k]][j + 2 * dy[k]] == '.' ? 1 : 0); if (a[i + dx[k]][j + dy[k]] == 'b' || a[i + 2 * dx[k]][j + 2 * dy[k]] == 'b') cap = INF; if (cap) f.addEdge(n*n + i*n + j, n*tx + ty, cap); } } } } printf("%d\n", f.stream(2 * n*n + 1, 2 * n*n + 2)); return 0; } | cs |
'알고리즘 관련 > BOJ' 카테고리의 다른 글
BOJ)2507 공주 구하기 (0) | 2017.06.18 |
---|---|
BOJ)12869 뮤탈리스크 (0) | 2017.06.18 |
BOJ)12963 달리기 (0) | 2017.06.15 |
BOJ)8217 유성 (1) | 2017.06.14 |
BOJ)14434 놀이기구1 (0) | 2017.06.14 |