题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1281
解题思路:
把棋盘的行x看成二分图左边的点,列y看成二分图右边的点,那么就把可以放车的位置看成是一条边,而二分图的最大匹配中x互不相同,y互不相同,所以每个匹配都是不同行不同列,所以最大匹配就是最多可以放的车的数量。
接下来就是关键边的查找了,这里实际可以每次删一条边,然后做二分匹配,看是否等于删边之前的最大匹配,如果是就说明刚刚删除的那条边并不影响增广路的增加。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 105;
int n,m,k,g[maxn][maxn];
int match[maxn],X[maxn],Y[maxn];
bool vis[maxn];
bool dfs(int u)
{
for(int i = 1; i <= n; i++)
{
if(g[u][i] > 0 && vis[i] == false)
{
vis[i] = true;
if(match[i] == -1 || dfs(match[i]))
{
match[i] = u;
return true;
}
}
}
return false;
}
int Max_Match()
{
int ans = 0;
memset(match,-1,sizeof(match));
for(int i = 1; i <= n; i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
ans++;
}
return ans;
}
int main()
{
int cas = 1;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(g,0,sizeof(g));
for(int i = 1; i <= k; i++)
{
scanf("%d%d",&X[i],&Y[i]);
g[X[i]][Y[i]] = 1;
}
int ans = Max_Match(),cnt = 0;
for(int i = 1; i <= k; i++)
{
g[X[i]][Y[i]] = 0;
int tmp = Max_Match();
if(tmp < ans) cnt++;
g[X[i]][Y[i]] = 1;
}
printf("Board %d have %d important blanks for %d chessmen.\n",cas++,cnt,ans);
}
return 0;
}