poj 2195 Going Home 二分图最大权匹配

       求二分图最小权匹配,转换成最大权匹配。

       方法一,初始化边e为负的权值,取反输出答案;

       方法二,lx[]用min初始化,求slack时用max, 从最小值逐渐增大。

       感觉二分图最大权匹配的思想与差分约束求最大值有些像。 差分约束求最大值一直保持d[u] <= d[v]+ e(u, v),而最大权匹配则是通过顶标,先从最大的权值边匹配,若不能构成完全匹配,就在相等子图里添加边。都是从最大值开始减少,当满足所有条件时,就是所求的最大值

       

#include <iostream>

#include <cstring>

#include <cstdio>

using namespace std;



const int N = 105;

const int INF = 1000000000;



int E[N][N];

bool map[N][N];

bool vis_x[N], vis_y[N];

int lx[N], ly[N];



int match[N];

char maze[N][N];

int row, col;

int man_count, house_count;

int slack;



int abs(int a)

{

	if (a < 0)

		return -a;

	return a;

}



bool dfs(int u, int n)

{

	int tmp;

	vis_x[u] = true;



	for (int i = 0; i < n; i++)

	{

		if (!vis_y[i])

		{

			tmp = lx[u] + ly[i] - E[u][i];

			if (tmp == 0)

			{

				vis_y[i] = true;

				if (match[i] == -1 || dfs(match[i], n))

				{

					match[i] = u;

					return true;

				}

			}

			else

				slack = max(tmp, slack);

		}

	}



	return false;

}



//最小权匹配

void KM(int n)

{

	for (int i = 0; i < n; i++)

	{

		lx[i] = INF; //-inf

		ly[i] = 0;

		for (int j = 0; j < n; j++)

			lx[i] = min(lx[i], E[i][j]); //若求最大权匹配用max

	}

	memset(match, -1, sizeof(match));

	for (int i = 0; i < n; i++)

	{	

		while (1)

		{

			memset(vis_x, false, sizeof(vis_x));

			memset(vis_y, false, sizeof(vis_y));

			

			slack = -INF; //inf

			if (dfs(i, n))

				break;



			for (int i = 0; i < n; i++)

			{

				if (vis_x[i]) lx[i] -= slack;

				if (vis_y[i]) ly[i] += slack;

			}

		}

	}

	

}



int main()

{

	while (scanf("%d%d", &row, &col))

	{

		if (row == 0 && col == 0)

			break;



		memset(E, 0, sizeof(E));

		man_count = 0;

		house_count = 0;

		for (int i = 0; i < row; i++)

		{

			getchar();

			for (int j = 0; j < col; j++)

				scanf("%c", &maze[i][j]);

		}



		//构图

		for (int i = 0; i < row; i++)

			for (int j = 0; j < col; j++)

				if (maze[i][j] == 'm')

				{

					house_count = 0;

					for (int a = 0; a < row; a++)

						for (int b = 0; b < col;  b++)

							if (maze[a][b] == 'H')

								E[man_count][house_count++] = abs(a-i) + abs(b-j);



					man_count++;

				}





		KM(man_count);

		int ans = 0;

		for (int i = 0; i < man_count; i++)

			ans += E[match[i]][i];



		printf("%d\n", ans);

	}

	return 0;

}

你可能感兴趣的:(home)