题目:http://acm.hdu.edu.cn/showproblem.php?pid=2426
注:
1) 二分图中边权为负值时,不匹配 (he still wants to design a creative plan such that no student is assigned to a room he/she dislikes)
2) KM算法中如果无法进行匹配成功,就会进入死循环 (所以我选择用最大二分匹配 先进行匹配)
3) 还有就是如果是邻接矩阵储存的话,要考虑到矩阵的初始化
源代码:
/*==============================================================================*\
二分图最佳匹配(kuhn munkras算法)
最大权匹配/最小权匹配,复杂度O(n^3)
\*==============================================================================*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define N 505 //N是X的顶点数最大值 M是Y的顶点数最大值
#define M 5005
#define INF 1e9
#define fin -10001 //g[][]的初值,绝对值大于边权的最大值
using namespace std;
int u,v,w,e;
int g[N][M],nx,ny; //需要初始化 nx是X的顶点数 ny是Y的顶点数
int mx[N],my[M],lx[N],ly[M]; //lx[],ly[]为KM算法中Xi与Yi的顶点标号 mx[]是匹配后X中对应的Y的顶点编号 my[]是匹配后Y中对应的X的顶点编号
bool sx[N],sy[N]; //标记是否在交错树上
int prev[N],slack[N]; //prev[i]为Y中i点在交错树上的前点;slack为松弛量
int q[2*N],head,tail;
bool chk[N]; //标记数组
bool search(int u)
{
for(int v=0;v<ny;v++)
if(g[u][v]>-1&&!chk[v])
{
chk[v]=true;
if(my[v]==-1||search(my[v]))
{
my[v]=u; mx[u]=v;
return true;
}
}
return false;
}
int Maxmatch()
{
int ret=0;
memset(mx,-1,sizeof(mx));
memset(my,-1,sizeof(my));
for(int u=0;u<nx;u++)
if(mx[u]==-1)
{
memset(chk,false,sizeof(chk));
if(search(u)) ret++;
}
return ret;
}
void augment(int v){ //增广
while(v!=-1){
int pv=mx[prev[v]];
mx[prev[v]]=v; my[v]=prev[v];v=pv;
}
}
bool bfs(){
while(head!=tail){
int p=q[head++],u=p>>1;
if(p & 1){
if(my[u]==-1){ augment(u);return true;
}
else { q[tail++]=my[u]<<1; sx[my[u]]=true;
}
}
else
for(int i=0;i<ny;i++)
if(sy[i]) continue;
else if(lx[u]+ly[i]!=g[u][i]){
int ex=lx[u]+ly[i]-g[u][i];
if(slack[i]>ex){ slack[i]=ex; prev[i]=u; }
}
else { prev[i]=u; sy[i]=true; q[tail++]=i*2+1; }
}
return false;
}
int KMmatch(bool maxsum ){ //默认为最大权匹配
int i,j,ex,cost=0;
if(!maxsum) for(i=0;i<nx;i++)
for(j=0;j<ny;j++) g[i][j]*=-1;
memset(mx,-1,sizeof(mx));
memset(my,-1,sizeof(my));
memset(ly,0,sizeof(ly));
for(i=0;i<nx;i++)
for(lx[i]=-INF,j=0;j<ny;j++)
lx[i]=max(lx[i],g[i][j]);
for(int live=0;live<nx;live++){
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
for(i=0;i<ny;i++)slack[i]=INF;
head=tail=0; q[tail++]=live*2; sx[live]=true;
while(!bfs()){
for(ex=INF,i=0;i<ny;i++) if(!sy[i]) ex=min(ex,slack[i]);
for(i=0;i<nx;i++) if(sx[i])lx[i]-=ex;
for(j=0;j<ny;j++){ if(sy[j])ly[j]+=ex;slack[j]-=ex;}
for(i=0;i<ny;i++)
if(!sy[i] && slack[i]==0){q[tail++]=i*2+1;sy[i]=true;}
}
}
if(!maxsum) for(i=0;i<nx;i++) for(j=0;j<ny;j++) g[i][j]*=-1;
for(i=0;i<nx;i++)cost+=g[i][mx[i]];
return cost;
}
int main()
{
int k=0;
//freopen("D:\\a.txt","r",stdin);
while(~scanf("%d %d %d",&nx,&ny,&e))
{
k++;
memset(g,fin,sizeof(g));
for(int i=0;i<e;i++)
{
scanf("%d %d %d",&u,&v,&w);
if(w>=0) g[u][v]=w;
}
if(Maxmatch()!=nx)
printf("Case %d: -1\n",k);
else
printf("Case %d: %d\n",k,KMmatch(true));
}
}
几组测试数据:
2 2 4
0 0 1
0 1 4
1 0 -1
1 1 1
2 1 2
0 0 2
1 0 3
3 3 3
0 0 8
1 0 9
2 2 10