一、题目描述
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);
}
}
本文探讨了如何使用匈牙利算法解决棋盘上放置车的问题,确保车无法互相攻击。通过建立二分图模型并进行匹配,找出最多可放置车的位置,并确定这些位置的重要性。
840

被折叠的 条评论
为什么被折叠?



