思路:最小费用最大流与最小割的区别就是有了一个变量记录费用的问题,并且在反向建图的时候费用为负值。
在建好图之后不停的找最短路,知道到终点的时候不存在最短路时停止。求解最小费用最大流时,就是用伴随网络来更新,原理和最短路的方法更新最大流类似。边找最短路,边更新可行流。
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<queue> #include<algorithm> #define MAX 1000 #define inf 0x3f3f3f3f using namespace std; char str[110]; struct node{ int x,y; }q1[110],q2[110]; int num1,num2,s,e,cnt,head[1000],cur[1000]; struct no{ int w,c,to,next; }q[100000]; int cost,dis[500],qq[100000],minflow,flow; bool vis[10000]; void add(int a,int b,int w,int c){ q[cnt].w=w; q[cnt].to=b; q[cnt].c=c; q[cnt].next=head[a]; head[a]=cnt++; q[cnt].w=0; q[cnt].to=a; q[cnt].c=-c;///** q[cnt].next=head[b]; head[b]=cnt++; } bool SPFA(){ minflow=inf; memset(dis,inf,sizeof(dis)); memset(vis,false,sizeof(vis)); dis[s]=0; int st,en; st=en=0; qq[st++]=s; cur[s]=-1; vis[s]=true; while(st>en){ int v=qq[en++]; vis[v]=false; for(int i=head[v];~i;i=q[i].next){ int u=q[i].to; if(dis[u]>dis[v]+q[i].c&&q[i].w>0 ){ dis[u]=dis[v]+q[i].c; if(minflow>q[i].w){ minflow=q[i].w; } cur[u]=i; if(!vis[u]){ qq[st++]=u; vis[u]=true; } } } } if(dis[e]>=inf) return 0; flow+=minflow; cost+=minflow*dis[e]; for(int i=cur[e];~i;i=cur[q[i^1].to] ){ q[i].w-=minflow; q[i^1].w+=minflow; } return 1; } int main(){ int n,m,i,j,l,k; while(~scanf("%d%d",&n,&m)){ if(!n&&!m) break; flow=cost=cnt=s=num1=num2=0; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++){ scanf("%s",str+1); for(j=1;j<=m;++j){ if(str[j]=='H'){ q1[++num1].x=i; q1[num1].y=j; } if(str[j]=='m'){ q2[++num2].x=i; q2[num2].y=j; } } } e=num1+num2+1; for(i=1;i<=num1;++i){ for(j=1;j<=num2;++j){ add(i,j+num1,1,abs(q2[j].x-q1[i].x)+abs(q2[j].y-q1[i].y ) ); } } for(i=1;i<=num1;i++){ add(s,i,1,0); } for(i=1;i<=num2;i++){ add(i+num1,e,1,0); } while(SPFA()); printf("%d\n",cost); } }