看完这道题,没什么思路,只知道求如何求第二问。看了别人题解突然恍然大悟。由于不能放车的地方不影响车的互相攻击,所以就相当于是列去匹配行,题目中给出的点(x,y),转化为g[x}[y}=1(只需要x->y即可),其他位置都是0。而求第一问,就是枚举每一个点,把它去掉之后再算一遍最大匹配,如果算出来 < ans2,说明它是关键点。这种思路和次小生成树的求法是一样的,
连暴力枚举都不会的渣渣=。=|||
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=105;
int n,m;
bool g[MAXN][MAXN];
int x[MAXN*MAXN],y[MAXN*MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)
{
for(int v=0;v<m;v++)
if(g[u][v]&&!used[v]){
used[v]=true;
if(linker[v]==-1||dfs(linker[v])){
linker[v]=u;
return true;
}
}
return false;
}
int hungary(void)
{
int res=0;
msc(linker);
for(int u=0;u<n;u++)
{
ms(used);
if(dfs(u)) res++;
}
return res;
}
int main(int argc, char const *argv[])
{
int k,ti=0;
while(scanf("%d %d %d",&n,&m,&k)==3)
{
ms(g);
for(int i=0;i<k;i++)
{
scanf("%d %d",x+i,y+i);
x[i]--;
y[i]--;
g[x[i]][y[i]]=true;
}
int ans1=0,ans2=hungary();
for(int i=0;i<k;i++)
{
g[x[i]][y[i]]=false;
if(hungary()<ans2) ans1++;
g[x[i]][y[i]]=true;
}
printf("Board %d have %d important blanks for %d chessmen.\n",
++ti,ans1,ans2);
}
return 0;
}