POJ 2195 Going Home KM/最小费用流
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; }