原题连接:点击打开链接
题意:…………
思路:求最多能放多少个 “车”,可以转化成 二分图的最大匹配!,把能放的点的 横纵座标 当作 二分图的一条边!最大匹配就满足了题目中任意两个“车”不会互相吃到的条件,因为匹配结果,会使得棋盘中的匹配点(也就是二分图中的匹配边),不在同一列且不再同一行。求出最大匹配后 ,则重要点必定在最大匹配的边上!依次去掉每条便,再求最大匹配看和原匹配是否相等即可!
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
vector<int>V[1000];
int link[1000],use[1000];
void init(int n)
{
int i;
for(i=0;i<=n;i++)
V[i].clear();
}
bool Dfs(int v)
{
int i,j,k;
for(i=0;i<V[v].size();i++)
{
k=V[v][i];
if(!use[k])
{
use[k]=1;
if(!link[k]||Dfs(link[k]))
{
link[k]=v;
return true;
}
}
}
return false;
}
int MaxMatch(int n)
{
int i,j,ans=0;
memset(link,0,sizeof(link));
for(i=1;i<=n;i++)
{
memset(use,0,sizeof(use));
if(Dfs(i))
ans++;
}
return ans;
}
int main()
{
int i,j,n,m,k,t=0;
while(~scanf("%d%d%d",&n,&m,&k))
{
t++;
init(n);
int x,y;
while(k--)
{
scanf("%d%d",&x,&y);
V[x].push_back(y);
}
int ans=MaxMatch(n);
int imp=0;
for(i=1;i<=n;i++)
{
for(j=0;j<V[i].size();j++)
{
k=V[i][j];
V[i].erase(V[i].begin()+j);
// printf("去掉边 %d----%d\n",i,k);
int cnt=MaxMatch(n);
if(cnt<ans)
imp++;
V[i].insert(V[i].begin()+j,k);
}
}
printf("Board %d have %d important blanks for %d chessmen.\n",t,imp,ans);
}
}