P - 奔小康赚大钱HDU 2255
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=333;
const int oo=0x3f3f3f3f;
int maps[maxn][maxn],lx[maxn],ly[maxn];
int visx[maxn],visy[maxn],s[maxn],used[maxn],n;
bool finds(int u)
{
visx[u]=1;
for(int i=1;i<=n;i++)
{
if(!visy[i]&&lx[u]+ly[i]==maps[u][i])
{
visy[i]=1;
if(!used[i]||finds(used[i]))//如果used[i]没有被占用 或者 被占用但是used[i]可以被让出来 返回真;
{
used[i]=u;
return true;
}
}
else//不满足则更新d;
{
s[i]=min(s[i],lx[u]+ly[i]-maps[u][i]);
}
}
return false;
}
int km()
{
memset(used,0,sizeof(used));
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
lx[i]=max(lx[i],maps[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
s[j]=oo;
}
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(finds(i))//如果找到增广路,退出 否则更新d继续寻找;
break;
int d=oo;
for(int j=1;j<=n;j++)
{
if(!visy[j])
{
d=min(d,s[j]);
}
}
for(int j=1;j<=n;j++)//如果在增光路中 则作出相应变化
{
if(visx[j])
lx[j]-=d;
if(visy[j])
ly[j]+=d;
}
}
}
int res=0;
for(int i=1;i<=n;i++)
{
res+=maps[used[i]][i];
}
return res;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&maps[i][j]);
}
}
printf("%d\n",km());
}
return 0;
}