POJ 2195 第一道最小费用流

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

#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值