貌似以前学的km算法都是背的=。=!一直有没怎么用,都忘记到爪哇国去了,这次赶快复习一下。
km什么的,就是通过设定顶标,慢慢压低定标,使得有足够的边进入相等子图,最后得到一个最大权匹配。
无脑裸代码就不贴了。
一道不求最大权匹配却使用km算法的题目:
给定一个n*m的矩阵,给矩阵的每个格子中填上数字,要求:1,相邻格子的数字之和大于等于他们的相邻的边的权值 。 2 .填的数字之和最小。
把矩阵黑白染色,建立二分图,格子的相邻边作为二分图的边,然后求一组km的顶标,定标的答案就是填的数字。
# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>
using namespace std;
const int oo=1073741819, maxn = 100*100;
int h[105][105],lx[maxn],ly[maxn],slack[maxn], point[maxn], top,linke[maxn*3], sum[maxn*3], wis[maxn*3], next[maxn*3];
bool vx[maxn], vy[maxn];
int ans,t1,t2,n,m;
inline int max(int x, int y) {return x>y?x:y;};
inline int min(int x, int y) {return x<y?x:y;};
void link(int x, int y, int z)
{
++top; next[top]=linke[x]; linke[x]= top; sum[top]=y; wis[top]=z;
lx[x]=max(lx[x], z);
}
bool find(int x)
{
vx[x]=true;
for (int ke=linke[x]; ke!=0;ke=next[ke])
{
int d=lx[x]+ly[sum[ke]]-wis[ke];
if ((!vy[sum[ke]])&& (!d))
{
vy[sum[ke]]=true;
if (point[sum[ke]]==0|| find(point[sum[ke]]))
{point[sum[ke]]=x; return true;};
} else slack[sum[ke]]=min(slack[sum[ke]], d);
}
return false;
}
int main()
{
int i,j,x;
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
scanf("%d%d", &n, &m);
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
if (i+j&1) h[i][j]=++t1; else h[i][j]=++t2;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
if (i+j&1)
{
scanf("%d", &x); if (i<n)link(h[i][j], h[i+1][j], x);
scanf("%d", &x); if (j<m)link(h[i][j], h[i][j+1], x);
}
else
{
scanf("%d", &x); if (i<n)link(h[i+1][j], h[i][j], x);
scanf("%d", &x); if (j<m)link(h[i][j+1], h[i][j], x);
}
}
int d;
for (i = 1; i <= t1; i++)
for (;;)
{
memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy));memset(slack,127,sizeof(slack));
if (find(i)) break;
for (d=oo,j=1;j<=t2;j++) if (!vy[j]) d=min(d,slack[j]);
for (j=1;j<=t1;j++) if (vx[j]) lx[j]-= d;
for (j=1;j<=t2;j++) if (vy[j]) ly[j]+= d;
}
for (ans=0,i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (i+j&1) ans+= lx[h[i][j]]; else ans+= ly[h[i][j]];
printf("%d\n", ans);
for (i=1;i<=n;i++)
{
for (j=1;j<=m; j++)
if (i+j&1) printf("%d ",lx[h[i][j]]); else printf("%d ", ly[h[i][j]]);
printf("\n");
}
return 0;
}