http://poj.org/problem?id=2195
题意:N个人 N个房子,问N个人进入N个房子一共最少走几步
KM算法,原理看了一天多,就是把 求最大权匹配的问题 转化成 求完备匹配的问题(x端点都被匹配,或者y端点都被匹配)
关于原理百度百科讲的不错 http://baike.baidu.com/view/739278.htm
总之,原理查了好多资料
还有一个地方,题目让求最小,KM用于求最大,所以做一些处理最后ans加个负号
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define Max(a,b)a>b?a:b
#define Min(a,b)a<b?a:b
#define inf 1000000
#define MAX 105
using namespace std;
int map[MAX][MAX],lx[MAX],ly[MAX],link[MAX];
bool vx[MAX],vy[MAX];
int n,m;
struct
{
int r,c;
}M[MAX],H[MAX];
bool dfs(int u)
{
int j;
vx[u]=1;
for(j=1;j<=m;j++)
if(!vy[j]&&map[u][j]==lx[u]+ly[j])//!!!map[u][j]==lx[u]+ly[j]
{
vy[j]=1;
if(!link[j]||dfs(link[j]))
{
link[j]=u;
return true;
}
}
return false;
}
int KM()
{
int i,j,k;
for(i=1;i<=n;i++)
{ lx[i]=-inf;
for(j=1;j<=m;j++)
lx[i]=Max(lx[i],map[i][j]);//每个map[i][j]都已初始化
}
memset(ly,0,sizeof(ly));
memset(link,0,sizeof(link));
for(i=1;i<=n;i++)
{
while(1)
{
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
if(dfs(i))break;
//修改 lx ly
int MIN=inf;
for(j=1;j<=n;j++)
if(vx[j])
for(k=1;k<=m;k++)
if(!vy[k])
MIN=Min(MIN,lx[j]+ly[k]-map[j][k]);
for(j=1;j<=n;j++)if(vx[j])lx[j]-=MIN;//lx[j]--;错错错
for(j=1;j<=m;j++)if(vy[j])ly[j]+=MIN;
}
}
int ans=0;
for(i=1;i<=m;i++)
if(link[i]) ans+=map[link[i]][i];
return ans;
}
int main()
{
int r,c,i,j;
char ch;
while(cin>>r>>c)
{
if(r==0&&c==0)break;
n=m=0;
for(i=1;i<=r;i++)
for(j=1;j<=c;j++)
{
cin>>ch;
if(ch=='m')
{
M[++n].r=i;
M[n].c=j;
}
else if(ch=='H')
{
H[++m].r=i;
H[m].c=j;
}
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
map[i][j]=-abs(M[i].r-H[j].r)-abs(M[i].c-H[j].c);
cout<<-KM()<<endl;
}
return 0;
}
又一次写这个题,WA了n次后,发现题意弄错了,题目没说有‘H'的格子不能走啊,每个方格都可以走,囧。。。以后不能想当然了 如果每个方格都能走的话,就不需要dfs搜索找最短路了。。。下面的代码是用的dfs找最短路,就浪费时间了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#define inf 1<<26
#define nMAX 200
using namespace std;
int n,r,c;
int link[nMAX],a[nMAX][nMAX],map[nMAX][nMAX],lx[nMAX],ly[nMAX];
bool vx[nMAX],vy[nMAX],vs[nMAX][nMAX];
int dir[4][2]={-1,0,0,1,1,0,0,-1};
struct node
{
int x,y,step;
}qu[nMAX*nMAX];
int min(int a,int b)
{
return a<b?a:b;
}
int max(int a,int b)
{
return a>b?a:b;
}
void bfs(int x,int y,int u)
{
int i,j,k,beg,tail;
beg=0,tail=1;
qu[0].x=x,qu[0].y=y,qu[0].step=0;
memset(vs,0,sizeof(vs));
vs[x][y]=1;
while(beg!=tail)
{
node tt,t=qu[beg++];
for(k=0;k<4;k++)
{
tt.x=t.x+dir[k][0],tt.y=t.y+dir[k][1];
if(tt.x<1||tt.x>r||tt.y<1||tt.y>c||vs[tt.x][tt.y])continue;
tt.step=t.step+1;
qu[tail++]=tt;
vs[tt.x][tt.y]=1;
if(a[tt.x][tt.y]>0)map[u][a[tt.x][tt.y]]=-tt.step;
}
}
}
bool DFS(int u)
{
int j;
vx[u]=1;
for(j=1;j<=n;j++)
{
if(!vy[j]&&map[u][j]==lx[u]+ly[j])
{
vy[j]=1;
if(link[j]==-1||DFS(link[j]))
{
link[j]=u;
return 1;
}
}
}
return 0;
}
int KM()
{
int i,j,k,MIN;
memset(link,-1,sizeof(link));
for(i=1;i<=n;i++)
{
lx[i]=-inf,ly[i]=0;
for(j=1;j<=n;j++)
lx[i]=max(lx[i],map[i][j]);
}
memset(link,-1,sizeof(link));
for(i=1;i<=n;i++)
{
while(1)
{
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
if(DFS(i))break;
MIN=inf;
for(j=1;j<=n;j++)
if(vx[j])
for(k=1;k<=n;k++)
if(!vy[k])
MIN=min(MIN,lx[j]+ly[k]-map[j][k]);
for(j=1;j<=n;j++)if(vx[j])lx[j]-=MIN;
for(j=1;j<=n;j++)if(vy[j])ly[j]+=MIN;
}
}
int sum=0;
for(i=1;i<=n;i++)
{// cout<<"map["<<link[i]<<"][="<<i<<"]="<<map[link[i]][i]<<endl;
if(link[i])sum+=map[link[i]][i];
}
return sum;
}
int main()
{
int i,j;
int sm,sh;
char ch;
while(~scanf("%d%d",&r,&c))
{
if(r==0&&c==0)break;
sm=0;
for(i=1;i<=r;i++)
{
getchar();
for(j=1;j<=c;j++)
{
scanf("%c",&ch);
if(ch=='H')a[i][j]=-1;
else if(ch=='m')a[i][j]=++sm;
else a[i][j]=0;
}
}
sh=0;
memset(map,0,sizeof(map));
for(i=1;i<=r;i++)
for(j=1;j<=c;j++)
{
if(a[i][j]==-1)bfs(i,j,++sh);
}
n=sh;
int ans=-KM();
printf("%d\n",ans);
}
return 0;
}