当前位置: 代码迷 >> 综合 >> POJ 2195 第一道最小费用流
  详细解决方案

POJ 2195 第一道最小费用流

热度:12   发布时间:2024-01-20 20:14:48.0

终于切掉了我的第一道最小费用流了...

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define MN 222
using namespace std;struct Home{ int i,j; }H[MN];
struct Man{ int i,j; }M[MN];
struct Edge{ int u,v,c,f,next,cost; }E[MN*MN];int head[MN],dis[MN],cur[MN],pre[MN];
int s,t,aug,min,EN,cntH,cntM,ans;int mmin( int a,int b ){ return a<b?a:b; }void addEdge( int u,int v,int c,int cc,int cost )
{E[EN].v=v; E[EN].c=c; E[EN].f=0;E[EN].cost=cost; E[EN].next=head[u]; head[u]=EN++;E[EN].v=u; E[EN].c=cc; E[EN].f=0;E[EN].cost=-cost; E[EN].next=head[v]; head[v]=EN++;
}void spfa()
{bool vis[MN];queue<int>Q;memset( vis,0,sizeof(vis) );memset( dis,0x3f,sizeof(dis) );Q.push(s);dis[s]=0;pre[s]=s;while( !Q.empty() ){int cv=Q.front();Q.pop();vis[cv]=false;for( int i=head[cv];i!=-1;i=E[i].next ){if( dis[E[i].v]>dis[cv]+E[i].cost && E[i].f<E[i].c ){pre[E[i].v]=cv;cur[E[i].v]=i;dis[E[i].v]=dis[cv]+E[i].cost;if( !vis[E[i].v] ){vis[E[i].v]=true;Q.push(E[i].v);}}}	  }
}int main()
{char G[MN][MN];int n,m;while( scanf("%d %d",&n,&m)!=EOF ){if( n==0 && m==0 )break;cntH=cntM=0;ans=0;EN=0;memset( head,-1,sizeof(head) );for( int i=0;i<n;i++ )scanf( "%s",&G[i] );for( int i=0;i<n;i++ ) for( int j=0;j<m;j++ )if( G[i][j]=='m' ){ M[cntM].i=i; M[cntM++].j=j; }else if( G[i][j]=='H' ){ H[cntH].i=i; H[cntH++].j=j; }s=0;t=cntH+cntM+1;for( int i=0;i<cntH;i++ )for( int j=0;j<cntM;j++ )addEdge( i+1,cntH+j+1,1,0,abs(H[i].i-M[j].i)+abs(H[i].j-M[j].j) );for( int i=0;i<cntH;i++ )addEdge( s,i+1,1,0,0 );for( int i=0;i<cntM;i++ )addEdge( cntH+i+1,t,1,0,0 );while( true ){aug=0x3f3f3f3f;spfa();//printf( "%d\n",aug );if( dis[t]==0x3f3f3f3f )break;for( int i=t;i!=s;i=pre[i] )aug=mmin( aug,E[cur[i]].c-E[cur[i]].f );for( int i=t;i!=s;i=pre[i] )	   E[cur[i]].f+=aug,E[cur[i]^1].f-=aug;ans+=aug*dis[t];}printf( "%d\n",ans );}return 0;
}