题意
给出一个N*M (1 < N,M <= 100) 的棋盘,规定只有某些格子可以放“車”。要求放置的“車”不能互相攻击(不在同一行同一列)
在保证尽量多的“車”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“車”被放下。但是某些格子若不放子,就无法保证放尽量多的“車”,这样的格子被称做重要点。求有多少个这样的重要点。
思路
匈牙利算法做二分图匹配。
匈牙利算法(简单易懂)
由于每一行每一列都只有一个“車”,相当于行、列做匹配,让车的数量最多就是相当于求最大匹配数。故先用匈牙利算法板子求出最开始的匹配数。
至于“重要点”,只需要暴力遍历一遍,依次将可以放的格子标记为不可放,每次跑匈牙利,如果匹配数减少了,说明该格子是重要点。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 105;
int g[maxn][maxn];
int match[maxn];
bool used[maxn];
struct node{
int x, y;
}p[maxn*maxn];
int n, m, k;
bool dfs(int v)
{
for(int j = 1; j <= m; j++){
if(g[v][j] && !used[j]){
used[j] = 1;
if(match[j] == 0 || dfs(match[j]) == 1){
match[j] = v;
return true;
}
}
}
return false;
}
int hungary()
{
int res = 0;
memset(match, 0, sizeof match);
for(int v = 1; v <= n; v++){
memset(used, 0, sizeof used);
if(dfs(v)) res++;
}
return res;
}
int main()
{
int kase = 0;
while( ~scanf("%d%d%d",&n,&m,&k) ){
memset(g, 0, sizeof g);
for(int i = 0; i < k; i++){
scanf("%d%d",&p[i].x,&p[i].y);
g[p[i].x][p[i].y] = 1;
}
int h = hungary();
int ans = 0;
for(int i = 0; i < k; i++){
g[p[i].x][p[i].y] = 0;
if(hungary() < h) ans++;
g[p[i].x][p[i].y] = 1;
}
printf("Board %d have %d important blanks for %d chessmen.
", ++kase, ans, h);
}
return 0;
}