poj 2195 Going Home

很裸的二分圖最優匹配

把每個‘m’距離其他所有的‘H’之間的權值求出,建立二分圖。求出最優匹配。

求最小權值,只需把所有的權值取相反數,求出最大權值,再取相反數。

 

求最優匹配,跟求網絡流思想一樣,中間有個轉換的思想,即有一個反悔的操作,網上資料一大堆呢!

 

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
#define INF 1000000

struct Node
{
	int x,y;
};

int g[150][150];
int x[150],y[150];
int visx[150],visy[150];
int link[150];
Node House[150],Man[150];
int nx,ny;
int slack;

int Cost(int i,int j)
{
	int x=abs(Man[i].x-House[j].x);
	int y=abs(Man[i].y-House[j].y);
	return -(x+y);
}

bool dfs(int u)
{
	visx[u]=1;
	for(int i=0;i<ny;i++)
		if( !visy[i] && g[u][i] )
		{			
			int t=x[u]+y[i]-g[u][i];
			if(t==0)
			{
				visy[i]=1;
				if( link[i]==-1 || dfs(link[i]) )
				{
					link[i]=u;
					return 1;
				}
			}
			else if(slack>t) slack=t;
		}
	return 0;
}

int K_M()
{
	memset(x,-INF,sizeof(x));
	memset(y,0,sizeof(y));
	for(int i=0;i<nx;i++)
		for(int j=0;j<ny;j++)
			if(x[i]<g[i][j])
				x[i]=g[i][j];
	memset(link,-1,sizeof(link));
	for(int i=0;i<nx;i++)
	{
		while(true)
		{
			memset(visx,0,sizeof(visx));
			memset(visy,0,sizeof(visy));
			slack=INF;
			if(dfs(i)) break;
			for(int i=0;i<nx;i++)
			{
				if( visx[i] )
					x[i]-=slack;
				if( visy[i] )
					y[i]+=slack;
			}
		}
	}
	int res=0;
	for(int i=0;i<nx;i++)
		res+=g[link[i]][i];
	return res;
}

int main()
{
//	freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d %d",&n,&m)==2 && (n||m) )
	{
		nx=ny=0;
		for(int i=0;i<n;i++)
		{
			getchar();
			for(int j=0;j<m;j++)
			{
				char c;
				scanf("%c",&c);
				if(c=='H')
				{
					House[ny].x=i;
					House[ny++].y=j;
				}
				if(c=='m')
				{
					Man[nx].x=i;
					Man[nx++].y=j;
				}
			}
		}
		memset(g,0,sizeof(g));
		for(int i=0;i<nx;i++)
			for(int j=0;j<ny;j++)
				g[i][j]=Cost(i,j);
		int ans=K_M();
		printf("%d\n",-ans);
	}	
	return 0;
}


 

發佈了72 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章