步骤:
#include <iostream> #include<cstdio> #include<cstring> using namespace std; #define MAX 310 #define INF 1<<25 #define clr(x) memset(x,0,sizeof(x)) /**注:发生矛盾,即几个居民同抢一个房子**/ int w[MAX][MAX]; int n; int lx[MAX],ly[MAX]; int link[MAX]; int slack[MAX]; int visx[MAX],visy[MAX]; bool dfs(int x) { visx[x]=1; /****得到发生矛盾的居民集合****/ for(int y=1;y<=n;y++) /**这个居民,每个房子都去试一试!(找到就退出)**/ { if(visy[y]) /****一个房子不需要重复访问****/ continue; int t=lx[x]+ly[y]-w[x][y];/****按这个标准去用-匈牙利算法***/ if(t==0)/**t==0标志这个房子可以给这位居民**/ { visy[y]=1; if(link[y]==0||dfs(link[y])) /****这房子没人住 或 可以让住这个房子的人去找另外的房子住****/ { link[y]=x; return true;/**那么就可以让这位居民住进来**/ } } else if(slack[y]>t)/**否则这个房子不能给这位居民!**/ slack[y]=t;/***就要找到这个房子要松弛多少才能够给这位居民***/ /***且当有多个居民都对这个房子有松弛量时,要找到最小的。****/ } return false; } int KM() { clr(lx); clr(ly); clr(link); /*****首先把每个居民出的钱最多的那个房子赋给它******/ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(lx[i]<w[i][j]) lx[i]=w[i][j]; /*****n循环-在满足了以前居民的情况下-给第i个居民安置房子*****/ for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) slack[j]=INF; /***松弛量***//****这个松弛量不需要每次dfs都初始化一次;因为它跟visy有关***/ while(1)/****死循环-在于一定要给这个居民找到房子为止!****/ { clr(visx); clr(visy); if(dfs(i)) /***找到房子就跳出死循环***/ break; int d=INF; for(int k=1;k<=n;k++) if(!visy[k]&&d>slack[k]) d=slack[k]; /****找到最小松弛量*****/ for(int k=1;k<=n;k++)/****松弛操作-使发生矛盾的居民有更多选择*****/ { if(visx[k]) /*****将矛盾居民的要求降低,使他们有更多可房子选择*****/ lx[k]-=d; if(visy[k]) /****使发生矛盾的房子在下一个子图,保持矛盾(即保持原子图性质)*****/ ly[k]+=d; } } } int ans=0; for(int i=1;i<=n;i++) ans+=w[link[i]][i]; return ans; } int main() { while(~scanf("%d",&n)) { clr(w);//每个案列都要重新置0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&w[i][j]);//输入每边权值 printf("%d\n",KM()); } return 0; }
原文:https://www.cnblogs.com/lijiahui-123/p/13383015.html