这题是KM的裸题啦。。
不解释 看了很久的文档,发现一篇文档很好的,其他的都写得很少。。
如果想要,就联系我吧。。
学KM之前先学匈牙利吧。。下面是步骤
算法流程:
(1)初始化可行顶标的值 将V1的点的标号记为与其相连边的最大边权值,V2的点标号全记为0
(2)用匈牙利算法在相等子图寻找完备匹配
(3)若未找到完备匹配则修改可行顶标的值 ,扩充相等子图
(4)重复(2)(3)直到找到相等子图的完备匹配为止
一种是朴素的O(N^4)的
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<string>
#define ll __int64
#define INF 0x7fffffffffffffff
#define inf 0x7fffffff
#define eps 1e-10
#define pi acos(-1.0)
#define FRE freopen("in.txt","r",stdin)
#define E exp(1.0)
#define log2(x) log((x))/log(2.0)
typedef long long LL;
#define maxn 310
using namespace std;
int g[maxn][maxn];
bool visx[maxn],visy[maxn];
int lx[maxn],ly[maxn];
int match[maxn];
int n;
bool Hungary(int u)
{
visx[u]=1;
int i;
for(i=0;i<n;i++)
{
if(!visy[i]&&lx[u]+ly[i]==g[u][i])
{
visy[i]=1;
if(match[i]==-1||Hungary(match[i]))
{
match[i]=u;
return true;
}
}
}
return false;
}
void KM()
{
int i,j,k;
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
lx[i]=max(lx[i],g[i][j]);
for(i=0;i<n;i++)
{
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(Hungary(i))
break;
else
{
int tmp=inf;
for(j=0;j<n;j++)
{
if(visx[j])
{
for(k=0;k<n;k++)
{
if(!visy[k]&&tmp>lx[j]+ly[k]-g[j][k])
tmp=lx[j]+ly[k]-g[j][k];
}
}
}
for(j=0;j<n;j++)
{
if(visx[j])
lx[j]-=tmp;
if(visy[j])
ly[j]+=tmp;
}
}
}
}
}
int main() {
FRE;
while(scanf("%d",&n)==1)
{
memset(match,-1,sizeof(match));
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&g[i][j]);
}
}
KM();
int ans=0;
for(i=0;i<n;i++)
ans+=g[match[i]][i];
printf("%d\n",ans);
}
return 0;
}
一种是优化后的 ,建议都用优化后的吧O(N^3)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<string>
#define ll __int64
#define INF 0x7fffffffffffffff
#define inf 0x7fffffff
#define eps 1e-10
#define pi acos(-1.0)
#define FRE freopen("in.txt","r",stdin)
#define E exp(1.0)
#define log2(x) log((x))/log(2.0)
typedef long long LL;
#define maxn 310
using namespace std;
int g[maxn][maxn];
bool visx[maxn],visy[maxn];
int lx[maxn],ly[maxn];
int match[maxn];
int slack[maxn];
int n;
bool Hungary(int u)
{
visx[u]=1;
int i;
for(i=0;i<n;i++)
{
if(visy[i])
continue;
if(lx[u]+ly[i]==g[u][i])
{
visy[i]=1;
if(match[i]==-1||Hungary(match[i]))
{
match[i]=u;
return true;
}
}
else
slack[i]=min(slack[i],lx[u]+ly[i]-g[u][i]);
}
return false;
}
void KM()
{
int i,j,k;
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
lx[i]=max(lx[i],g[i][j]);
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
slack[j]=inf;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(Hungary(i))
break;
else
{
int tmp=inf;
for(j=0;j<n;j++)
{
if(!visy[j])
{
if(tmp>slack[j])
tmp=slack[j];
}
}
for(j=0;j<n;j++)
{
if(visx[j])
lx[j]-=tmp;
if(visy[j])
ly[j]+=tmp;
else
slack[j]-=tmp;
}
}
}
}
}
int main() {
FRE;
while(scanf("%d",&n)==1)
{
memset(match,-1,sizeof(match));
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&g[i][j]);
}
}
KM();
int ans=0;
for(i=0;i<n;i++)
ans+=g[match[i]][i];
printf("%d\n",ans);
}
return 0;
}