简单的二分图匹配问题。把每一个可放棋子的横纵左边用边连起来,直接求最大匹配就是ans。然后题目还要求出重要的边,所以前面输入可放棋子的横纵坐标要记录起来,接下来每次删掉一条边,再求最大匹配,若小于ans,说明这是条重要的边。同时每次匹配完都要把删去的边补回来。
/*
46MS 292K
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define SIZE 105
using namespace std;
int N,M,K,ans,need;
bool cnt[SIZE][SIZE],vis[SIZE];
int link[SIZE];
int x[SIZE*SIZE],y[SIZE*SIZE];
bool dfs(int l)
{
for(int r=1; r<=M; r++)
{
if(!vis[r] && cnt[l][r])
{
vis[r] = true;
if(link[r] == -1 || dfs(link[r]))
{
link[r] = l;
return true;
}
}
}
return false;
}
int main()
{
int Case = 1;
while(~scanf("%d%d%d",&N,&M,&K))
{
memset(cnt,0,sizeof(cnt));
memset(link,-1,sizeof(link));
for(int i=1; i<=K; i++)
{
int s,e;
scanf("%d%d",&s,&e);
cnt[s][e] = true;
x[i] = s;
y[i] = e;
}
ans = need = 0;
for(int i=1; i<=N; i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans ++;
}
for(int i=1; i<=K; i++)
{
cnt[x[i]][y[i]] = false;
memset(link,-1,sizeof(link));
int temp = 0;
for(int j=1; j<=N; j++)
{
memset(vis,0,sizeof(vis));
if(dfs(j))
temp ++;
}
if(temp < ans)
need ++;
cnt[x[i]][y[i]] = true;
}
printf("Board %d have %d important blanks for %d chessmen.\n",Case++,need,ans);
}
return 0;
}