传送门HDU 1281

描述

小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
棋盘游戏(特殊建图匈牙利)

输入

输入包含多组数据,
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。

输出

对输入的每组数据,按照如下格式输出:
Board T have C important blanks for L chessmen.

样例

  • Input
    3 3 4
    1 2
    1 3
    2 1
    2 2
    3 3 4
    1 2
    1 3
    2 1
    3 2
  • Output
    Board 1 have 0 important blanks for 2 chessmen.
    Board 2 have 3 important blanks for 3 chessmen.

题解

我们把行和列分开看成两个点集,可以放棋子的格子就看作两点(某行和某列)之间的对应关系,这样的话就形成一个二分图,如果有两个棋子能相互攻击的话就说明他们在同一行或者同一列,所以该图的最大匹配就是最多能放的棋子个数。然而题中所说的重要点的意思就是,如果去掉这一个格子(也就是二分图中一条边),二分图的最大匹配就会减少。我们只需要枚举每一个格子求出删掉它后的最大匹配值,如果算出来比一开始的最大匹配小,那么这个格子就是重要点

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
#define LL long long int
#define INIT(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,b,a) for(int i=b-1;i>=a;i--)
//b——0,-1,128,0x3f,127 ,字符
const double Pi = acos(-1);
const double E = exp(1.0);
const LL mod =1e9+7;
const int MAX=0x7fffffff;
const int MIN=-0x7fffffff;
const int INF=0x3f3f3f3f;
using namespace std;
int line[505][505],used[505],another[505];
int n,m;
int find(int x)
{
for(int i=1;i<=m;i++)
{
if(line[x][i]==1&&used[i]==0){
used[i]=1;
if(another[i]==0||find(another[i])){
another[i]=x;
return 1;
}
}
}
return 0;
}
int count()
{
int sum=0;
for(int i=1;i<=n;i++)
{
INIT(used,0);
if(find(i))sum++;
}
return sum;
}
int main()
{
ios::sync_with_stdio(false);
int k,x[10005],y[10005],_=1;
while(~scanf("%d %d %d",&n,&m,&k))
{
INIT(another,0);INIT(line,0);
for(int i=0;i<k;i++)
{
scanf("%d %d",&x[i],&y[i]);
line[x[i]][y[i]]=1;
}
int all=count(),sum=0;
for(int i=0;i<k;i++)
{
line[x[i]][y[i]]=0;
INIT(another,0);//注意这里每一次求的最大匹配都是相互独立的,所以要清空
if(count()<all)sum++;
line[x[i]][y[i]]=1;
}
printf("Board %d have %d important blanks for %d chessmen.\n",_,sum,all);
_++;
}
return 0;
}

相关文章: