题目大意:
给定n,有n间宿舍 每间4人
接下来n行 是第一年学校规定的宿舍安排
接下来n行 是第二年学生的宿舍安排意愿
求满足学生意愿的最少交换次数
input
2
1 2 3 4
5 6 7 8
4 6 7 8
1 2 3 5
output
2
#include <bits/stdc++.h> #define MAXN 205 #define INF 0x3f3f3f3f using namespace std; int n,mint; int G1[MAXN][5],G2[MAXN][5]; int G[MAXN][MAXN],link[MAXN]; int x[MAXN],y[MAXN]; int visx[MAXN],visy[MAXN]; bool DFS(int s) { visx[s]=1; for(int i=1;i<=n;i++) { if(visy[i]) continue; int tmp=x[s]+y[i]-G[s][i]; if(tmp==0) { visy[i]=1; if(link[i]==-1 || DFS(link[i])) { link[i]=s; return true; } } else if(tmp > 0) { mint=min(mint,tmp); } } return false; } void KM() { for(int i=1;i<=n;i++) { link[i]=-1; y[i]=x[i]=0; for(int j=1;j<=n;j++) x[i]=max(x[i],G[i][j]); } for(int i=1;i<=n;i++) { while(1) { mint =INF; memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(i)) break; for(int i=1;i<=n;i++) { if(visx[i]) x[i]-=mint; if(visy[i]) y[i]+=mint; } } } int out=0; for(int i=1;i<=n;i++) out+=G[link[i]][i]; printf("%d ",4*n-out); } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) for(int j=1;j<=4;j++) scanf("%d",&G1[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=4;j++) scanf("%d",&G2[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int cnt=0; for(int p=1;p<=4;p++) for(int q=1;q<=4;q++) if(G1[i][p]==G2[j][q]) cnt++; G[i][j]=cnt; } KM(); } return 0; }
KM算法讲解
https://blog.csdn.net/sixdaycoder/article/details/47720471
https://blog.csdn.net/c20180630/article/details/71080521
int n,mint; int G[MAXN][MAXN],link[MAXN]; int x[MAXN],y[MAXN]; int visx[MAXN],visy[MAXN]; bool DFS(int s) { visx[s]=1; for(int i=1;i<=n;i++) { if(visy[i]) continue; int tmp=x[s]+y[i]-G[s][i]; if(tmp==0) { visy[i]=1; if(link[i]==-1 || DFS(link[i])) { link[i]=s; return true; } } else if(tmp > 0) { mint=min(mint,tmp); } } return false; } void KM() { for(int i=1;i<=n;i++) link[i]=-1; for(int i=1;i<=n;i++) { while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(i)) break; for(int i=1;i<=n;i++) { if(visx[i]) x[i]-=mint; if(visy[i]) y[i]+=mint; } } } }