-
[11493] 동전 교환BOJ 2022. 11. 23. 22:10
https://www.acmicpc.net/problem/11493
11493번: 동전 교환
입력의 첫줄에는 테스트 케이스의 수 T가 주어진다. 각 테스트 케이스의 첫줄에는 정수 n과 m (1 ≤ n ≤ 500, n-1 ≤ m ≤ n(n-1)/2 )이 주어진다. 여기서 n은 정점의 개수, m은 간선의 개수를 나타낸다.
www.acmicpc.net
#include <bits/stdc++.h>using namespace std;#ifdef ONLINE_JUDGEconstexpr bool local = false;#elseconstexpr bool local = true;#endifusing ll = long long;using pi = pair<ll, ll>;constexpr int MAX_V = 1005; // 최대 정점 개수constexpr int S = 1001; // 소스 정점 번호constexpr int E = 1002; // 싱크 정점 번호constexpr int INF = 1'000'000'000;int n, m, tar;int c[MAX_V][MAX_V]; // 각 간선의 용량int d[MAX_V][MAX_V]; // 각 간선의 비용int f[MAX_V][MAX_V]; // 각 간선에 흐르는 중인 유량vector<int> adj[MAX_V]; // 각 정점의 인접 리스트int a[MAX_V]; // 정점의 색int b[MAX_V]; // 동전의 색void solve(void) {int ans = 0;int cnt = 0;// MCMF 시작while (1) {int prev[MAX_V], dst[MAX_V];bool inQ[MAX_V] = {0}; // 해당 정점이 큐 안에 있는가?queue<int> Q;memset(prev, -1, sizeof(prev));fill(dst, dst + MAX_V, INF);dst[S] = 0;inQ[S] = true;Q.push(S);
while (!Q.empty()) {int curr = Q.front();Q.pop();inQ[curr] = false; // 큐에서 꺼냄for (int next : adj[curr]) {// 최단 경로를 찾는 중이지만, 여전히 여유 용량 있어야 함if (c[curr][next] - f[curr][next] > 0 anddst[next] > dst[curr] + d[curr][next]) {dst[next] = dst[curr] + d[curr][next];prev[next] = curr;// 큐에 들어있지 않다면 큐에 넣음if (!inQ[next]) {Q.push(next);inQ[next] = true;}}}}if (prev[E] == -1) break;
int flow = INF;for (int i = E; i != S; i = prev[i])flow = min(flow, c[prev[i]][i] - f[prev[i]][i]);cnt += flow;for (int i = E; i != S; i = prev[i]) {ans += (flow * d[prev[i]][i]);f[prev[i]][i] += flow;f[i][prev[i]] -= flow;}}// printf("%d %d\n", cnt, tar);cout << ans << '\n';}void init() {tar = 0;memset(c, 0, sizeof(c));memset(f, 0, sizeof(f));memset(d, 0, sizeof(d));memset(a, 0, sizeof(a));memset(b, 0, sizeof(b));for (int i = 0; i < MAX_V; i++) adj[i].clear();}int main(void) {if (!local) ios_base::sync_with_stdio(0), cin.tie(0);int t;cin >> t;while (t--) {init();cin >> n >> m;int i, j;for (i = 1; i <= m; i++) {int x, y;cin >> x >> y;adj[x].push_back(y);adj[y].push_back(x);}for (i = 1; i <= n; i++) cin >> a[i];for (i = 1; i <= n; i++) cin >> b[i];for (i = 1; i <= n; i++) {if (a[i] == 0 and b[i] == 1) {// 소스와 연결int x = S, y = i;adj[x].push_back(y);adj[y].push_back(x);c[x][y] = 1;tar++;}}for (i = 1; i <= n; i++) {if (a[i] == 1) {queue<int> q;// assert(q.empty());int dst[MAX_V];fill(dst, dst + MAX_V, INF);q.push(i);dst[i] = 0;while (!q.empty()) {int cur = q.front();q.pop();for (int nxt : adj[cur]) {if (1 <= nxt and nxt <= n);elsecontinue;if (dst[nxt] == INF) {dst[nxt] = dst[cur] + 1;q.push(nxt);}}}for (j = 1; j <= n; j++) {if (b[j] == 1) {int x = j, y = i + 500, cost = dst[j];
// printf("(%d %d %d)\n", x, y, cost);adj[x].push_back(y);adj[y].push_back(x);c[x][y] = INF;d[x][y] = cost;d[y][x] = -cost;}}}}for (i = 1; i <= n; i++) {if (a[i] == 1 and b[i] == 0) {// 싱크와 연결int x = i + 500, y = E;adj[x].push_back(y);adj[y].push_back(x);c[x][y] = 1;}}solve();}return 0;}
'BOJ' 카테고리의 다른 글
[5545] 최고의 피자 (0) 2023.05.07 [14653] 너의 이름은 (0) 2023.03.02 [12971] 숫자 놀이 (0) 2022.08.11 [10775] 공항 (0) 2022.08.02 lazy 세그 - 비재귀 (0) 2022.07.26