HDU 1281

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1281

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Problem Description
小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。 
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
 
Input
输入包含多组数据, 
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
 
Output
对输入的每组数据,按照如下格式输出: 
Board T have C important blanks for L chessmen.
 
Sample Input
3 3 4
1 2
1 3
2 1
2 2
3 3 4
1 2
1 3
2 1
3 2
 
Sample Output
Board 1 have 0 important blanks for 2 chessmen.
Board 2 have 3 important blanks for 3 chessmen.
 
题解:
参考http://www.cnblogs.com/dilthey/p/7647870.html博文中的方法②;
因为这次没有墙能隔开车与车之间的攻击,故直接将整行整列缩成点,然后求出max match;
但是如何寻找其中的“必须边”呢?
比较好想的方法就是直接暴力枚举最大匹配中的匹配边,如果把它去掉还能不能得到一样的最大匹配数:
如果不能,就是必须边,cnt+=1;
 
AC代码:
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define MAX 203
 5 using namespace std;
 6 int n,m,k;
 7 int edge[MAX][MAX];
 8 int matching[MAX];
 9 int vis[MAX];
10 void init(){memset(edge,0,sizeof(edge));}
11 void add_edge(int u,int v){edge[u][v]=edge[v][u]=1;}
12 bool dfs(int u)
13 {
14     for(int v=1;v<=n+m;v++)
15     {
16         if(!edge[u][v]) continue;
17         if (!vis[v])
18         {
19             vis[v]=1;
20             if(!matching[v] || dfs(matching[v]))
21             {
22                 matching[v]=u;
23                 matching[u]=v;
24                 return true;
25             }
26         }
27     }
28     return false;
29 }
30 int hungarian()
31 {
32     int ret=0;
33     memset(matching,0,sizeof(matching));
34     for(int i=1;i<=n;i++)
35     {
36         if(!matching[i])
37         {
38             memset(vis,0,sizeof(vis));
39             if(dfs(i)) ret++;
40         }
41     }
42     return ret;
43 }
44 int mp[103][103],match[MAX][MAX];
45 int main()
46 {
47     int kase=0;
48     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
49     {
50         memset(mp,0,sizeof(mp));
51         for(int i=1,r,c;i<=k;i++)
52         {
53             scanf("%d%d",&r,&c);
54             mp[r][c]=1;
55         }
56 
57         init();
58         for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(mp[i][j]) add_edge(i,j+n);
59         int max_match=hungarian();
60 
61         int cnt=0;
62         memset(match,0,sizeof(match));
63         for(int i=1;i<=n+m;i++) for(int j=n+1;j<=n+m;j++) if(matching[i]==j && matching[j]==i) match[i][j]=1;
64         for(int i=1;i<=n+m;i++)
65         {
66             for(int j=n+1;j<=n+m;j++)
67             {
68                 if(match[i][j])
69                 {
70                     edge[i][j]=0;
71                     if(hungarian()<max_match) cnt++;
72                     edge[i][j]=1;
73                 }
74             }
75         }
76 
77         printf("Board %d have %d important blanks for %d chessmen.
",++kase,cnt,max_match);
78     }
79 }
原文地址:https://www.cnblogs.com/dilthey/p/7663065.html