这题明显是裸的二分图的最优匹配
关于二分图最优匹配的两篇博客
http://www.cnblogs.com/zxndgv/archive/2011/08/17/2142015.html
http://blog.163.com/suntroop@yeah/blog/static/17012103120115185927194/
最小权匹配和最大权匹配相对,有两种写法:
第一种是在建图的时候将所有边的权值取反,求出最大权匹配后将权值取反。
第二种是在建图的时候将顶标lx[]和ly[]的意义稍微改一下,将lx取成所有相连的边中权值最小的,ly初始化为0不变,然后更新lx[]值时加,而ly[]减,且更新最小数d时需将t取反。
某渣还是太弱了,只会贴模版。。。 还是不懂
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 333
bool visx[maxn], visy[maxn];
int map[maxn][maxn];
int lx[maxn], ly[maxn], match[maxn];
int n, d, ans;
void init()
{
memset(match, -1, sizeof(match));
for(int i= 1; i<= n; i++)
{
lx[i]= ly[i]= 0;
for(int j= 1; j<= n; j++)
{
scanf("%d",&map[i][j]);
lx[i]= max(map[i][j], lx[i]);
}
}
}
bool dfs(int u)
{
visx[u]= 1;
for(int i= 1; i<= n; i++)
if(!visy[i])
{
int t= lx[u]+ ly[i]- map[u][i];
if(t== 0)
{
visy[i]= 1;
if(match[i]== -1 || dfs(match[i]))
{
match[i]= u;
return true;
}
}
else if(t> 0)
d= min(d, t);
}
return false;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
ans= 0;
for(int i= 1; i<= n; i++)
{
d= 1<< 30;
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
while(!dfs(i))
{
for(int j= 1; j<= n; j++)
{
if(visx[j]) lx[j]-= d;
if(visy[j]) ly[j]+= d;
}
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
}
}
for(int i= 1; i<= n; i++)
ans+= lx[i] + ly[i];
printf("%d\n",ans);
}
return 0;
}