链接:
https://www.nowcoder.com/acm/contest/143/E
题意:
给定n个宿舍的新安排, 每个宿舍都有4个人, 问要至少有多少个人换位才能变成新安排。
可以建一个二分图, 左边n个点为原来的安排, 右边n个点为新安排, 每条边花费设为( 4 - 交集), 然后跑费用流。
#include<bits/stdc++.h> using namespace std; const int maxN = 300; const int maxM = 1e5 + 7; const int INF = 1e9 + 7; int n, ecnt, S, T; struct { int to, w, cost, nxt; } edge[maxM]; struct Node{ int v, id; }pre[maxN]; int head[maxN]; int bef[maxN][4], after[maxN][4]; void init() { memset(head, -1, sizeof(head)); ecnt = 0; } void addEdge(int u, int v, int w, int c) { edge[ecnt].to = v; edge[ecnt].w = w; edge[ecnt].cost = c; edge[ecnt].nxt = head[u]; head[u] = ecnt++; } inline int dif(int a, int b) { int res = 4; for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { if(bef[a][i] == after[b][j]) { res--; break; } } } return res; } void build() { S = 0, T = 2 * n + 1; for(int i = 1; i <= n; i++) { addEdge(S, i, 1, 0); addEdge(i, S, 0, 0); addEdge(i + n, T, 1, 0); addEdge(T, i + n, 0, 0); } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { int c = dif(i, j); addEdge(i, j + n, 1, c); addEdge(j + n, i, 0, -c); //建反向边的时候注意花费要为负 } } } int vis[maxN], cost[maxN]; bool spfa(){ queue<int> q; memset(vis, 0, sizeof(vis)); fill(cost ,cost + maxN, INF); vis[S] = 1; cost[S] = 0; q.push(S); while(!q.empty()){ int u = q.front(); for(int i = head[u]; i != -1; i = edge[i].nxt){ int v = edge[i].to, f = edge[i].w , c = edge[i].cost; if(f == 0 || cost[v] <= cost[u] + c) continue; cost[v] = cost[u] + c; pre[v].v = u; pre[v].id = i; if(!vis[v]){ q.push(v); vis[v] = true; } } vis[u] = 0; q.pop(); } return cost[T] != INF; } int MCMF(){ int flow = 0; int minCost = 0; while(spfa()){ int minFlow = INF; for(int i = T; i != S; i = pre[i].v){ minFlow = min(minFlow, edge[pre[i].id].w); } for(int i = T; i != S; i = pre[i].v){ edge[pre[i].id].w -= minFlow; edge[pre[i].id ^ 1].w += minFlow; } minCost += cost[T]; } return minCost; } int main() { // freopen("1.txt","r", stdin); ios::sync_with_stdio(false); cin >> n; init(); for(int i = 1; i <= n; i++) for(int j = 0; j < 4; j++) cin >> bef[i][j]; for(int i = 1; i <= n; i++) for(int j = 0; j < 4; j++) cin >> after[i][j]; build(); cout << MCMF() << "\n"; }