hdu1507 Uncle Tom's Inherited Land*--最大匹配

本文介绍了一个关于二维矩阵的最大匹配问题,通过构建二分图并运用匈牙利算法来解决该问题。具体实现包括了如何构建二分图、如何进行深度优先搜索以找到匹配,并最终输出匹配路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1507


题意:一个n*m的矩阵,有k个格子被约束,在未被约束的格子中找到最多的组数满足:

1.每组两个格子;

2.两个格子相邻;

3.两个格子都不能被约束;

4.任何组的两个格子不能重复;


解析:其实很简单,建个二分图,求解最大匹配数,再输出路径即可。

建图左边是:下标和(i+j)为偶数;奇数放在右边。


我的图是以【1,1】为起点的,然后【1,2】,【1,3】,,,,,【2,1】,【2,2】,,,,


#define _CRT_SECURE_NO_DEPRECATE 

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>

#define INF 99999999;
using namespace std;

int n, m, k;
int a[105][105];
int cx[10005];
int cy[10005];
int vis[10005];
int dir[4][2] = { 0,1,-1,0,0,-1,1,0 };
vector<int> vec[10005];

int dfs(int u)
{
	for (int i = 0; i < vec[u].size(); i++)
	{
		int v = vec[u][i];
		if (!vis[v])
		{
			vis[v] = 1;
			if (cy[v] == -1 || dfs(cy[v]))
			{
				cx[u] = v;
				cy[v] = u;
				return 1;
			}
		}
	}
	return 0;
}

int hungarian()
{
	memset(cx, -1, sizeof(cx));
	memset(cy, -1, sizeof(cy));
	int ans = 0;
	for (int u = 1; u <= n*m; u++)
	{
		if (cx[u] == -1)
		{
			memset(vis, 0, sizeof(vis));
			ans += dfs(u);
		}
	}
	return ans;
}


int main()
{
	int x, y;
	while (~scanf("%d%d", &n, &m) && (n || m))
	{
		scanf("%d", &k);
		memset(a, 0, sizeof(a));
		for (int i = 0; i < k; i++)
		{
			scanf("%d%d", &x, &y);
			a[x][y] = 1;
		}

		for (int i = 1; i <= n*m; i++)
			vec[i].clear();

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if ((i + j) % 2 == 0 && a[i][j] != 1)
				{
					for (int p = 0; p < 4; p++)
					{
						int ii = i + dir[p][0];
						int jj = j + dir[p][1];
						if (ii >= 1 && ii <= n&&jj >= 1 && jj <= m&&a[ii][jj] != 1)
							vec[(i - 1)*m + j].push_back((ii - 1)*m + jj);//注意在i等于1的时候(i - 1)*m + j得到的值并不是我们想要的
					}
				}
			}
		}

		int maxMatch = hungarian();
		printf("%d\n", maxMatch);

		int x1, y1, x2, y2;
		for (int u = 1; u <= n*m; u++)
		{
			if (cx[u] != -1)
			{
				x1 = (u - 1) / m + 1;
				y1 = (u - 1) % m + 1;
				
				int v = cx[u];
				x2= (v - 1) / m + 1;
				y2= (v - 1) % m + 1;
				printf("(%d,%d)--", x2, y2);
				printf("(%d,%d)\n", x1, y1);
				//printf("%d  %d\n", u, v);
			}
		}
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值