POJ2195

裸的最小费用流,当然也可以用KM算法解决,但是比较难写。

注意反向边的距离为正向边的相反数(因此要用SPFA)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=302,src=301,sink=300,INF=1e+8; 
int n,m,man,house,x[maxn],y[maxn],cap[maxn][maxn],w[maxn][maxn];
vector<int> next[maxn];


void addedge(int a,int b)
{
 next[a].push_back(b);next[b].push_back(a);
 cap[a][b]=1;cap[b][a]=0;
}

int ab(int xx)
{
 if(xx<0)return xx*(-1);
 	else return xx;
}
int fa[maxn];
int len(int a,int b)
{
 if((a==src)||(a==sink)||(b==src)||(b==sink))return 0;
 return ab(x[b]-x[a])+ab(y[b]-y[a]);
}
bool inq[maxn];
int times[maxn],dist[maxn];
bool SPFA()
{
 
 memset(inq,0,sizeof(inq));
 for(int i=0;i<maxn;i++)
 	dist[i]=INF;
 dist[src]=0;
 queue<int>q;
 q.push(src);
 inq[src]=true;
 while(!q.empty())
 	{
 	 int now=q.front(); 
	 q.pop();
	 inq[now]=false;
	 for(int i=0;i<next[now].size();i++)
	 	{
	 	 int np=next[now][i];
	 	 if((dist[np]>dist[now]+w[now][np])&&cap[now][np]>0)
	 	 	{
	 	 	 dist[np]=dist[now]+w[now][np];
	 	 	 fa[np]=now;
	 	 	 if(!inq[np]){q.push(np);inq[np]=true;}
			}
		}	
	}
 if( dist[sink]<INF)return true;
 	else return false;
}

int augment()

{
 int u=sink,delta=INF;
 while(u!=src)
 	{
 	 if(cap[fa[u]][u]<delta)delta=cap[fa[u]][u];
 	 u=fa[u];
	} 
 u=sink;
 while(u!=src)
 	{
 	 cap[fa[u]][u]-=delta;
 	 cap[u][fa[u]]+=delta;
 	 u=fa[u];
	}
 return  dist[sink]*delta;
}

int main()
{ios::sync_with_stdio(false);
 while(cin>>n>>m)
 	{
 	 if(n==0&&m==0)return 0;
 	 man=0;house=150;
 	 memset(cap,0,sizeof(cap));memset(w,0,sizeof(w));
 	 for(int i=0;i<maxn;i++)
 	 	while(next[i].size()>0)next[i].pop_back();
 	 for(int i=0;i<n;i++)
 	 	{    
 	        
	  		for(int j=0;j<m;j++)
 	    		{
 	    		 char c;
 	    		 cin>>c;
 	    		 if(c=='m')
 	    		 	{
 	    		 	  x[man]=i;y[man]=j;
 	    		 	  man++;
					}
 	             if(c=='H')
 	             	{
 	             	  x[house]=i;y[house]=j;
 	             	  house++;
					}
				}
		}
	 for(int i=150;i<house;i++)
	 	{
	 	 addedge(i,sink);
	 	 for(int j=0;j<man;j++)
	 	 	addedge(j,i);
		}
	 for(int j=0;j<man;j++) addedge(src,j);
	 int ans=0;
	 for(int i=0;i<man;i++)
	 	for(int j=150;j<house;j++)
	 		{
	 		 w[i][j]=len(i,j);
	 		 w[j][i]=w[i][j]*(-1);
			}
 	 while(SPFA())
 		{
	 	 ans+=augment();
		}
	 cout<<ans<<endl;
	}
 
 
 return 0;
}

  

,没什么别的了,很简单。

 

posted on 2017-02-25 16:16  Bingsen  阅读(134)  评论(0编辑  收藏  举报