P1559 運動員最佳匹配問題 最大費用最大流
阿新 • • 發佈:2020-11-14
P1559 運動員最佳匹配問題 費用流
題目連結
雖然思想不難, 但是寫了好久, 原因是網路流都忘得差不多了, 這相當於複習了.
最大費用最大流.
炒雞源點向男生連一條費用為0, 流量為1的邊.女生想炒雞匯點連一條費用為0,流量為1的邊.所有男生想女生連一條費用為\(p[i][j] * q[j][i]\), 流量為1的邊.
流量都為1可以確保一個男生對應一個女生.思想挺簡單的.
#include <bits/stdc++.h> using namespace std; inline long long read() { long long s = 0, f = 1; char ch; while(!isdigit(ch = getchar())) (ch == '-') && (f = -f); for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48)); return s * f; } const int N = 25; int n, s, t, ans, cnt; int in[N], dis[N], pre[N], incf[N], head[N], p[N][N], q[N][N]; struct edge { int to, nxt, val, cost; } e[N * N + 2 * N]; void add(int x, int y, int z, int f) { e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z; e[cnt].cost = f; } int spfa() { queue <int> q; for(int i = 0;i <= t; i++) dis[i] = -1e9; q.push(s); dis[s] = 0; in[s] = 1; incf[0] = 1e9; while(!q.empty()) { int x = q.front(); q.pop(); in[x] = 0; for(int i = head[x]; i ; i = e[i].nxt) { if(!e[i].val) continue; int y = e[i].to; if(dis[y] < dis[x] + e[i].cost) { dis[y] = dis[x] + e[i].cost; pre[y] = i; incf[y] = min(incf[x], e[i].val); if(!in[y]) in[y] = 1, q.push(y); } } } return dis[t] != -1e9; } void up() { int p = t; while(p != s) { int i = pre[p]; e[i].val -= incf[t]; e[i ^ 1].val += incf[t]; p = e[i ^ 1].to; ans += e[i].cost * incf[t]; } } int main() { n = read(); s = 0, t = 2 * n + 1; cnt = 1; for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) p[i][j] = read(); for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) q[i][j] = read(); for(int i = 1;i <= n; i++) add(s, i, 1, 0), add(i, s, 0, 0); for(int i = n + 1;i <= 2 * n; i++) add(i, t, 1, 0), add(t, i, 0, 0); for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) add(i, j + n, 1, p[i][j] * q[j][i]), add(j + n, i, 0, -p[i][j] * q[j][i]); while(spfa()) up(); printf("%d", ans); return 0; }