• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

  • 联系
  • 订阅
  • 管理

View Post

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

posted on 2011-02-09 16:01  sysuwhj  阅读(659)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3