HDU 2255 & KM模板
题意:
一张完备二分图求最优完备匹配。
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);
}
}
Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.

浙公网安备 33010602011771号