您的位置:首页 > 其它

pku 2400

2011-07-19 21:03 267 查看
题意:求最小权匹配的所有匹配方案
分析:用km()算法求得最小匹配后,对于所有的 lx[i] + ly[[j] = g[i][j] 的 i ,j 建边 i---->j。然后求新建图的所有完美匹配(dfs即可)
代码:

#include<stdio.h>
#include<string.h>

#define N 20
#define inf 1000000000
int lx
,ly
,vx
,vy
,x
,y
;
int g

,slack
;
char map

;
int a

,b

;
int m,n,num;
int search(int u)
{
int v;vx[u]=1;
for(v=1;v<=n;v++)
{
if(vy[v]) continue;
if(lx[u]+ly[v]==g[u][v])
{
vy[v]=1;
if(y[v]==-1||search(y[v]))
{
x[u]=v;y[v]=u;
return 1;
}
}
else if(lx[u]+ly[v]-g[u][v]<slack[v])
slack[v]=lx[u]+ly[v]-g[u][v];
}
return 0;
}
int KM()
{
int i,j,min,ans;
memset(ly,0,sizeof(ly));
memset(x,-1,sizeof(x));
memset(y,-1,sizeof(y));
for(i=1;i<=m;i++)
{
for(lx[i]=-inf,j=1;j<=n;j++)
if(lx[i]<g[i][j])
lx[i]=g[i][j];
}
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
slack[j]=inf;
while(x[i]==-1)
{
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
if(search(i)) break;
//更新顶标
for(min=inf,j=1;j<=n;j++)
if(!vy[j]&&slack[j]<min)
min=slack[j];
for(j=1;j<=m;j++)
if(vx[j]) lx[j]-=min;
for(j=1;j<=n;j++)
if(vy[j]) ly[j]+=min;
else slack[j]-=min;
}
}
for(ans=0,i=1;i<=n;i++)
{
if(y[i]==-1) return -1;//无匹配
if(g[y[i]][i]==-inf) return -1;
ans+=g[y[i]][i];
}
return ans;
}
void dfs(int i)
{
int j;
if(i==n+1)
{
printf("Best Pairing %d\n",num++);
for(j=1;j<=n;j++)
printf("Supervisor %d with Employee %d\n",j,x[j]);
return ;
}
for(j=1;j<=n;j++)
if(map[i][j]&&!vy[j])
{
vy[j]=1;x[i]=j;
dfs(i+1);
vy[j]=0;
}
}
int main()
{
int t,i,j,k,cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
m=n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&k);
b[i][k]=j-1;
}
for(i=1;i<=n;i++)
for(j=0;j<n;j++)
{
scanf("%d",&k);
a[i][k]=j;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=-(a[i][j]+b[j][i]);
int ans=-1*KM();
printf("Data Set %d, Best average difference: %lf\n",cas++,(ans*1.0)/(2*n*1.0));
memset(map,0,sizeof(map));
memset(vy,0,sizeof(vy));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(lx[i]+ly[j]==g[i][j])
map[i][j]=1;
num=1;
dfs(1);
if(t!=0)printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: