반응형
문제 출처 :
https://www.acmicpc.net/problem/11495
알고리즘 분석 :
문제 해결에 필요한 사항
1. 네트워크 플로우
2. 그래프 모델링
이 문제는 http://kks227.blog.me/220804885235?Redirect=Log&from=postView 링크를 참고하여 제작하였습니다.
격자 0 만들기 문제는 위와 같이 파란색, 빨간색으로 분리를 시켜 생각하면 편하다.
그 이유는 가로 혹은 세로의 값을 뺄때 파란색 하나와 인접한 빨간색 하나를 선택해야만 하기 때문이다.
따라서 우리는 sink와 파란색을 연결해주고 source와 빨간색을 서로 연결해준 뒤, 각 서로 인접해있는 파란색, 빨간색을 연결하는 그래프 모델링을 하고 최대 유량 알고리즘을 이용하면 우리는 원하는 결과값을 얻을 수 있다.
이때 정답은 격자값을 모두 0으로 만드는 최소 횟수 이므로 최대 유량 f + 남은 나머지 t 이다.
남은 나머지 t는 다르게 표현하면 격자값에 있는 모든 총 합을 s라 하면 s - 2*f로 표현 할 수 있다.
따라서 우리는 f + s - 2*f이므로 s - f를 정답으로 도출할 수 있다.
소스 코드 :
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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | #include <iostream> #include <cstdio> #include <memory.h> #include <queue> #include <vector> #include <algorithm> #define fastio() ios::sync_with_stdio(0),cin.tie(0); using namespace std; const int INF = 987654321; const int RED = 1500; int arr[55][55]; pair<int, int> map[55][55]; vector<int> adj[3011]; int c[3011][3011]; int f[3011][3011]; int dx[4] = { -1,0,1,0 }; int dy[4] = { 0,-1,0,1 }; int S = 0, T = 3003; int main() { fastio(); int tc; cin >> tc; while (tc--) { int n, m; cin >> n >> m; memset(arr, 0, sizeof(arr)); memset(c, 0, sizeof(c)); memset(f, 0, sizeof(f)); memset(map, 0, sizeof(map)); for (int i = 0; i < 3011; i++) adj[i].clear(); vector<int> blue, red; int total = 0; bool chk = true; // blue일때 true int r = 1, b = 1; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> arr[i][j]; total += arr[i][j]; if (chk) { blue.push_back(arr[i][j]); map[i][j] = { 1, b++ }; } else { red.push_back(arr[i][j]); map[i][j] = { -1, r++ }; } chk = !chk; } if (m % 2 == 0) chk = !chk; } r = 1 + RED, b = 1; for (int i = 0; i < blue.size(); i++) { c[S][b] = blue[i]; adj[S].push_back(b); adj[b].push_back(S); b++; } for (int i = 0; i < red.size(); i++) { c[r][T] = red[i]; adj[r].push_back(T); adj[T].push_back(r); r++; } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (map[i][j].first == 1) { for (int k = 0; k < 4; k++) { int ni = i + dy[k]; int nj = j + dx[k]; if (!(0 <= ni && ni < n) || !(0 <= nj && nj < m)) continue; int b = map[i][j].second; int r = map[ni][nj].second + RED; c[b][r] = INF; adj[b].push_back(r); adj[r].push_back(b); } } } } int totalFlow = 0; while (1) { vector<int> prev(3004, -1); queue<int> q; q.push(S); while (!q.empty() && prev[T] == -1) { int here = q.front(); q.pop(); for (int i = 0; i < adj[here].size(); i++) { int next = adj[here][i]; if (prev[next] != -1) continue; if (c[here][next] - f[here][next] > 0) { q.push(next); prev[next] = here; } } } if (prev[T] == -1) break; int flow = INF; for (int i = T; i != S; i = prev[i]) flow = min(flow, c[prev[i]][i] - f[prev[i]][i]); for (int i = T; i != S; i = prev[i]) { f[prev[i]][i] += flow; f[i][prev[i]] -= flow; } totalFlow += flow; } cout << total - totalFlow << endl; } return 0; } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[14846번] 직사각형과 쿼리 (4) | 2017.11.17 |
---|---|
[11066번] 파일 합치기 (0) | 2017.11.16 |
[1658번] 돼지 잡기 (2) | 2017.11.14 |
[2866번] 문자열 잘라내기 (0) | 2017.11.13 |
[9996번] 한국이 그리울 땐 서버에 접속하지 (0) | 2017.11.13 |