构图思想,KM——pku3686

左集合毫无疑问n
右集合如何构造就可以建立良好的对应关系
3 4
1 100 100 100
99 1 99 99
98 98 1 98
可以拆点建立该图
就是把j点拆成3份
对应关系就出来了
1 2 3 100 200 300 100 200 300 100 200 300
99 198 297 1 2 3 99 198 297 99 198 297
98 196 294 98 196 294 1 2 3 98 196 294
View Code
#include<stdio.h>
#include
<string.h>

#define MAXN 2509
#define inf 1000000000
#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)
int mat[59][2509];
int temp[59][59];

int match1[MAXN];
int match2[MAXN];

int KM(int m,int n)
{
int s[MAXN],t[MAXN],l1[MAXN],l2[MAXN],p,q,ret=0,i,j,k;
for (i=0;i<m;i++){
for (l1[i]=-inf,j=0;j<n;j++)
l1[i]
=mat[i][j]>l1[i]?mat[i][j]:l1[i];
//if(l1[i]==-inf)return -1;???????-1
}

for (i=0;i<n;l2[i++]=0);
for (_clr(match1),_clr(match2),i=0;i<m;i++){
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (k=s[p],j=0;j<n&&match1[i]<0;j++)
if (l1[k]+l2[j]==mat[k][j]&&t[j]<0){
s[
++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]
=k=t[j],p=match1[k],match1[k]=j;
}
if (match1[i]<0){
for (i--,p=inf,k=0;k<=q;k++)
for (j=0;j<n;j++)
if (t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]<p)
p
=l1[s[k]]+l2[j]-mat[s[k]][j];
for (j=0;j<n;l2[j]+=t[j]<0?0:p,j++);
for (k=0;k<=q;l1[s[k++]]-=p);
}
}
for (i=0;i<m;i++)
{
ret
+=mat[i][match1[i]];
}
return ret;
}

int main()
{
int t,n,m;
scanf(
"%d",&t);
while(t--)
{
scanf(
"%d%d",&n,&m);
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++){
scanf(
"%d",&temp[i][j]);
}
}

int k;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
for(k=0;k<n;k++){
mat[i][j
*n+k]=-temp[i][j]*(k+1);
}
}
}

double ret=-KM(n,n*m)*1.0/n;//左集合数n,右集合变成n*m
printf("%.6lf\n",ret);
}
}

  

原文地址:https://www.cnblogs.com/huhuuu/p/2113519.html