题意:
一张完备二分图求最优完备匹配。
SOL:
这题就不讲什么sol了。。。毕竟是裸的KM,不会的话可以看老人家的大白鼠,一些问题看代码注释。讲讲经历(悲惨的经历)
刚打完,自信地交上去发现MLE...一脸大雾...然后才开始看数据..300^4啊...看起来会炸的样子,那么加个优化好了。还是MLE!真是奇了怪了。然后就在提交里看别人是不是用的邻接表——清一色邻接矩阵!再想想KM搞的都是完备图啊邻接表和邻接矩阵用起来没什么不同。那么没问题啊?然后交来交去交了8次...直到zyh大神——虽然他从不用KM,但是他居然一眼道出真相——没看到递归啊。
woc!!!HDU!!!显然我是爆栈了!!终于经历了一次爆栈的体验啊。。。也不枉此生了。
CODE:
/*========================================================================== # Last modified: 2016-02-16 18:17 # Filename: hdu2255.cpp # Description: ==========================================================================*/ #define me AcrossTheSky #include <cstdio> #include <cmath> #include <ctime> #include <string> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <set> #include <map> #include <stack> #include <queue> #include <vector> #define lowbit(x) (x)&(-x) #define INF 0x3f3f3f3f #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) #define FORP(i,a,b) for(int i=(a);i<=(b);i++) #define FORM(i,a,b) for(int i=(a);i>=(b);i--) #define ls(a,b) (((a)+(b)) << 1) #define rs(a,b) (((a)+(b)) >> 1) #define maxn 310 using namespace std; typedef long long ll; typedef unsigned long long ull; /*==================split line==================*/ int n; int slack[maxn],w[maxn][maxn],lx[maxn],ly[maxn],link[maxn]; //lx,ly表示节点函数,link表示T集每点对应的S集点 bool S[maxn],T[maxn]; //是否在相等子图中 bool match(int x){ S[x]=true; FORP(i,1,n){ if (T[i]) continue; if (lx[x]+ly[i]==w[x][i]){ T[i]=true; if (!link[i] || match(link[i])){ link[i]=x; return true; } } else slack[i]=min(slack[i],lx[x]+ly[i]-w[x][i]); //用slack计算出松弛量 } return false; } void updata(){ int a=INF; FORP(j,1,n) if (!T[j]) a=min(a,slack[j]); FORP(i,1,n) { if (S[i]) lx[i]-=a; if (T[i]) ly[i]+=a; else slack[i]-=a; } return; } void KM(){ memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); FORP(i,1,n){ link[i]=0; //S[i]=T[i]=false; FORP(j,1,n) lx[i]=max(lx[i],w[i][j]); } FORP(i,1,n){ //这里要循环N次我一直有点雾... FORP(j,1,n) slack[j]=INF; while(1){ memset(S,false,sizeof(S)); memset(T,false,sizeof(T)); if (match(i)) break; else updata(); } } } int main(){ while (scanf("%d",&n)==1){ FORP(i,1,n) FORP(j,1,n) { scanf("%d",&w[i][j]); } KM(); int ans=0; FORP(i,1,n) if (link[i]) //计算边权和 ans+=w[link[i]][i]; printf("%d\n",ans); } }
时间: 2024-10-13 00:13:46