hdu1045 行列缩点+二分图匹配

题意:目标是尽可能多地在城市中设置碉堡,这样就不会有两个碉堡相互摧毁。如果没有两个碉堡在地图的同一水平行或垂直列上,除非至少有一个墙将它们分开,否则碉堡的配置是合法的。在这个问题中,我们将考虑小方形城市(最多4x4),其中包含无法穿过子弹的墙壁。
下图显示了同一块板的五张图片。第一张图片是空白板,第二张和第三张图片显示合法配置,第四张和第五张图片显示非法配置。对于该板,合法配置中的最大块仓数为5; 第二张图片显示了一种方法,但还有其他几种方法。
您的任务是编写一个程序,在给定地图描述的情况下,计算可以在合法配置中放置在城市中的最大数量的阻止房屋。

分析:一开始看见这题我并不是很知道怎么写,不清楚怎么建图,看了题解才理解,这道题是一个求二分图最大匹配的题目,关键在于怎么建图。他由于你放了一个点,你就不能在同一行,同一列上在放一个点,就是去分别行列锁点建图。把同一列的不被阻碍的作为同一点,把同一行不被阻碍的作为同一点。然后建图就是建立行与列之间的联系。如图
在这里插入图片描述
你某一个点在这个列上占据了一定的格子数,然后就在那个占领格子数的位置的缩行点的那个点的值建立联系。举个例子,上图左边(1,1)(2,1)缩成一个点1;
然后在同样的位置行缩点那里(1,1)是缩成点1,(2,1)是缩成点3.所以就建立1与1,1与3的联系。按照这个步骤去做图在求最大匹配也就是答案了。为什么这样去求二分图匹配就是答案?因为你是建立了行与列之间的联系,就是你某个点选了后,已经无法再选另一个在这个点的范围点的另外的点如左边格子数(1,1)和(2,1)被缩成点1,你就不会去表示到(1,1)和(2,1)同时取的情况,这两个互斥点只会去选取一个(对于列),然后对于行也是同理的。所以满足条件的个数也就是最大匹配数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<time.h>
#include<cmath>
#define ll long long
using namespace std;
const long long max_ = 1e3 + 7;
int tu[max_][max_];
char node[max_][max_];
int diany[max_][max_], numy = 0, numx = 0;
int read()
{
	int s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
int n, m, e, vis[max_], match[max_];
int dfs(int now) {
	for (int i = 1; i <= numy; i++) {
		if (tu[now][i] && !vis[i]) {
			vis[i] = 1;
			if (match[i] == 0 || dfs(match[i])) {
				match[i] = now;
				return 1;
			}
		}
	}
	return 0;
}
void qing() {
	numy = 0, numx = 0;
	memset(tu ,0, sizeof(tu));
	memset(match, 0, sizeof(match));
	memset(vis, 0, sizeof(vis));
	memset(diany, 0, sizeof(diany));
	memset(node, '\0', sizeof(node));
}
int main() {
	
	while(cin>>n&&n!=0) {
		qing();
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				cin>> node[i][j];
			}
		}
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (node[i][j] != 'X') numy++;
				while (node[i][j]!='X' && j <= n)
				{
					diany[i][j] = numy;
					j++;
				}
			}
		}
		for (int j = 1; j <= n; j++) {
			for (int i = 1; i <= n; i++) {
				if (node[i][j] != 'X')numx++;
				while (node[i][j] != 'X'&& i <= n)
				{
					if (diany[i][j] != diany[i - 1][j]) {
						tu[numx][diany[i][j]] = 1;
					}
					i++;
				}
			}
		}
		int sum = 0;
		for (int i = 1; i <= numx; i++) {
			memset(vis, 0, sizeof(vis));
			sum += dfs(i);
		}
		cout << sum << endl;
		
	}
	
	return 0;
}

发布了32 篇原创文章 · 获赞 3 · 访问量 670

猜你喜欢

转载自blog.csdn.net/qq_43804974/article/details/101120136