hdu 2255 奔小康赚大钱(最佳匹配)
直接模版。。
#include <stdio.h>
#include <memory.h>
#define Min(X,Y) X<=Y?X:Y;
#define SIZE 305
#define INF 0x7f7f7f7f
long n;
long match[SIZE],edge[SIZE][SIZE],lx[SIZE],ly[SIZE],slack[SIZE];
char vstx[SIZE],vsty[SIZE];
bool DFS(long x){
long i;
vstx[x]=1; //访问标志置1
for(i=0;i<n;i++){
if(vsty[i]==0&&edge[x][i]==lx[x]+ly[i]){
vsty[i]=1;
if(match[i]==-1||DFS(match[i])){ //i没被访问过可直接构造或者通过该点能间接构造增广路
match[i]=x;
return true;
}
}
else if(edge[x][i]!=lx[x]+ly[i]) //不能构造增广路,松驰对应值
slack[i]=Min(slack[i],lx[x]+ly[i]-edge[x][i]);
}
return false;
}
long KM(){
long i,j,sum,mn;
memset(match,-1,sizeof(match[0])*n);
for(i=0;i<n;i++){
while(1){
memset(vstx,0,sizeof(vstx[0])*n);
memset(vsty,0,sizeof(vsty[0])*n);
memset(slack,0x7f,sizeof(slack[0])*n); //松驰值初始化无穷大
if(DFS(i)==1) //有增广路则break,否则修改顶标值
break;
mn=INF;
for(j=0;j<n;j++)
if(vsty[j]==0) mn=Min(mn,slack[j]); //求最小的松弛值
for(j=0;j<n;j++){
if(vstx[j]==1) lx[j]-=mn; //交错子树中X中的顶标-mn
if(vsty[j]==1) ly[j]+=mn; //交错子树中Y中的顶标+mn
if(vsty[j]==0) slack[j]-=mn; //非交错子树中的Y的顶点松驰值-mn
}
}
}
sum=0;
for(i=0;i<n;i++)
sum+=lx[i]+ly[i];//加上所有顶标值
return sum;
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
long i,j;
while(scanf("%ld",&n)!=EOF){
memset(ly,0,sizeof(ly[0])*n);
for(i=0;i<n;i++){
for(j=0;j<n;j++){
scanf("%ld",&edge[i][j]);
if(lx[i]<edge[i][j])
lx[i]=edge[i][j];
}
}
printf("%ld\n",KM());
}
return 0;
}
浙公网安备 33010602011771号