题目大意:在一张棋盘上给定k个点可以放置车,想要在车之间不互相攻击的情况下放置尽可能多的车(假设为x个)。现在定义这样的点为重要点,如果将该点去掉,就不能放下x个车。求k个点中有几个重要点?
题解:对于棋盘问题,可以根据棋盘的行与列建立二分图。在每个棋子的行与列之间连一条边,如果两个棋子不共行也不共列,那么这两条边就没有公共的顶点,那么这样就可以转化为求二分图的最大匹配数。然后我们依次枚举k个点,如果该点去掉之后最大匹配数改变,则该点就是重要点。这样就可以将一个陌生的问题转化为我们数值的匈牙利算法问题。
AC代码
#include<bits/stdc++.h>
using namespace std;
int n, m, k;
const int maxn = 105;
int edge[maxn][maxn], vis[maxn], link[maxn]; //vis[]数组我称为临时预定数组,vis[j] = a表示一轮模拟匹配中,女孩j被男孩a预定了。
int dfs(int l)
{
for (int r = 1; r <= m; r++)
{
if (edge[l][r] && !vis[r])
{
vis[r] = 1;
if (link[r] == -1 || dfs(link[r]))
{
link[r] = l;
return 1;
}
}
}
return 0;
}
int hungary()
{
int ans = 0;
memset(link, -1, sizeof(link));
for (int i = 1; i <= n; i++)
{
memset(vis, 0, sizeof(vis));
if (dfs(i))ans++;
}
return ans;
}
int main()
{
int T = 1;
while (scanf("%d%d%d", &n, &m, &k))
{
memset(edge, 0, sizeof(edge));
for (int i = 1; i <= k; i++)
{
int x, y;
cin >> x >> y;
edge[x][y] = 1;
}
int ans = hungary();
int important = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (edge[i][j])
{
edge[i][j] = 0;
if (hungary() != ans)important++;
edge[i][j] = 1;
}
}
}
printf("Board %d have %d important blanks for %d chessmen.\n", T++, important, ans);
}
}
如果觉得对你有帮助那就点个赞吧!