HDU 1281 棋盘游戏 二分图最大匹配

一、内容

 小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?

Input

输入包含多组数据,
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。

Output

对输入的每组数据,按照如下格式输出:
Board T have C important blanks for L chessmen.

Sample Input

3 3 4
1 2
1 3
2 1
2 2
3 3 4
1 2
1 3
2 1
3 2

Sample Output

Board 1 have 0 important blanks for 2 chessmen.
Board 2 have 3 important blanks for 3 chessmen.

二、思路

  • 每行可以看做左边的点,每列可以看做右边的点,若该位置(x,y)可以放车的话,那么就连一条x–>y的边。
  • 如何求关键点呢, 实际上当我们枚举所有匹配好的边,删除一条边后,再求一次最大匹配,如果最大匹配数不变的话,说明这个点不是关键点。若减少了,那么代表这个点必须要拿上。

三、代码

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 105;
int n, m, k, x, y, mat[N], mat2[N];
bool g[N][N], vis[N]; 
bool dfs(int u) {
	for (int v = 1; v <= m; v++) {
		if (vis[v] || !g[u][v]) continue; vis[v] = true;
		if (!mat[v] || dfs(mat[v])) {
			mat[v] = u; return true;
		}
	}
	return false;
}
int find() {
	int ans = 0;
	memset(mat, 0, sizeof(mat));
	for (int i = 1; i <= n; i++) {
		memset(vis, false, sizeof(vis));
		if (dfs(i)) ans++;
	}
	return ans;
} 
int main() {
	int T = 1;
	while (~scanf("%d%d%d", &n, &m, &k)) {
		memset(g, false, sizeof(g));
		for (int i = 1; i <= k; i++) {
			scanf("%d%d", &x, &y); g[x][y] = true;
		}
		int L = find(), C = 0;
		//找出所有匹配的点将边删除后 看是否还是能和L相等 
		memcpy(mat2, mat, sizeof(mat));
		for (int v = 1; v <= n; v++) {
			if (!mat2[v]) continue;
			int u = mat2[v]; 
			g[u][v] = false; 
			int t = find();
			if (t != L) C++;
			g[u][v] = true;  //恢复 
		} 
		printf("Board %d have %d important blanks for %d chessmen.\n", T++, C, L);
	}
	return 0;
}
发布了458 篇原创文章 · 获赞 468 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104480802
今日推荐