看完這道題,沒什麼思路,只知道求如何求第二問。看了別人題解突然恍然大悟。由於不能放車的地方不影響車的互相攻擊,所以就相當於是列去匹配行,題目中給出的點(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;
}