【代码超详解】HDU 1281 棋盘游戏(二分图匹配)

本文探讨了如何使用匈牙利算法解决棋盘上放置车的问题,确保车无法互相攻击。通过建立二分图模型并进行匹配,找出最多可放置车的位置,并确定这些位置的重要性。

一、题目描述

http://acm.hdu.edu.cn/showproblem.php?pid=1281

二、算法分析说明与代码编写指导

已知:处于同一行或同一列的车可以相互攻击。若要使放在棋盘上的车不能相互攻击,应该让每一行、每一列都只有一个车。
本题的难点在于建立图论模型。
设二分图 G(V1, V2, E)。每一行、每一列的点分别映射到 V1、V2,如果位置 (x, y) 允许放车,则将对应的两点 (x, y + n) 连一条无向边。
然后用匈牙利算法做一次二分图匹配,获得的最大匹配边数是实际上最多能够放车的格子数目。
由于数据量较小(n,m ≤ 100),因此可以暴力枚举每一个点:将这个点标记为不允许放车,然后在删掉相应边后的二分图上再跑一次匈牙利算法,当最大匹配数减少时,该点为重要点。

三、AC 代码

#include<cstdio>
#include<vector>
#include<bitset>
#pragma warning(disable:4996)
using namespace std;
const unsigned nmax = 101;
unsigned n, m, k, c, t, u, v, match[2 * nmax], MATCH[2 * nmax], a, T; bitset<2 * nmax> vis, g[2 * nmax];
bool dfs(const unsigned& u) {
	for (unsigned v = 1; v <= t; ++v) {
		if (vis[v] || !g[u][v])continue;
		vis[v] = true;
		if (!match[v] || dfs(match[v])) { match[v] = u; match[u] = v; return true; }
	}
	return false;
}
inline unsigned hungary() {
	unsigned r = 0; fill(match + 1, match + 1 + t, 0);
	for (unsigned i = 1; i <= n; ++i) { vis.reset(); if (dfs(i))++r; }
	return r;
}
int main() {
	for (;;) {
		if (scanf("%u%u%u", &n, &m, &k) == EOF)return 0;
		t = n + m; c = 0;
		for (unsigned i = 1; i <= t; ++i)g[i].reset();
		for (unsigned i = 0; i < k; ++i) {
			scanf("%u%u", &u, &v); g[u][v + n] = g[v + n][u] = true;
		}
		a = hungary(); copy(match + 1, match + 1 + t, MATCH + 1);
		for (unsigned v = 1; v <= n; ++v) {
			if (!MATCH[v])continue;
			u = MATCH[v]; g[u][v] = g[v][u] = false;
			if (hungary() != a)++c;
			g[u][v] = g[v][u] = true;
		}
		printf("Board %u have %u important blanks for %u chessmen.\n", ++T, c, a);
	}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值