hdu 1281

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

思路:把棋盘的行x看成二分图左边的点,列y看成二分图右边的点,那么就把可以放车的位置看成是一条边,而二分图的最大匹配中x互不相同,y互不相同,所以每个匹配都是不同行不同列,所以最大匹配就是最多可以放的车的数量。而要判断有多少个点是必须放的,只要在得出最大匹配后,每次去掉一个匹配,再去运算看得出的结果是否与原来的最大匹配数相同,若相同就不是必须的,若不相同就是必须的。

View Code
 1 #include<iostream>
 2 const int MAXN=110;
 3 using namespace std;
 4 int m,n,k;
 5 int X[MAXN],Y[MAXN];
 6 int cx[MAXN],cy[MAXN];
 7 int map[MAXN][MAXN];
 8 bool mark[MAXN];
 9 
10 int dfs(int u){
11     //考虑所以yi顶点v
12     for(int v=1;v<=n;v++){
13         //u与v邻接且没有被访问过
14         if(!mark[v]&&map[u][v]){
15             mark[v]=1;
16             //如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到一条增广路
17             if(cy[v]==-1||dfs(cy[v])){
18                 cy[v]=u;//把u匹配给v
19                 cx[u]=v;//把v匹配给u
20                 return 1;
21             }
22         }
23     }
24     return 0;
25 }
26 
27 //匈牙利算法
28 int MaxMatch(){
29     int res=0;
30     memset(cx,-1,sizeof(cx));//从1匹配开始增广,将cx,cy各元素初始化为-1.
31     memset(cy,-1,sizeof(cy));
32     for(int i=1;i<=n;i++){
33         //从每个未盖点出发寻找增广路
34         if(cx[i]==-1){
35             memset(mark,false,sizeof(mark));
36             //每寻找到一条增广路可使匹配数增加1
37             if(dfs(i)){
38                 res++;
39             }
40         }
41     }
42     return res;
43 }
44 
45 int main(){
46     int _case=1;
47     while(~scanf("%d%d%d",&n,&m,&k)){
48         memset(map,0,sizeof(map));
49         for(int i=1;i<=k;i++){
50             scanf("%d%d",&X[i],&Y[i]);
51             map[X[i]][Y[i]]=1;
52         }
53         int ans=MaxMatch();//求二分图最大匹配的匈牙利算法
54         int count=0;
55         for(int i=1;i<=k;i++){
56             map[X[i]][Y[i]]=0;//试着去掉每一条边
57             int res=MaxMatch();
58             map[X[i]][Y[i]]=1;//恢复
59             if(res<ans)count++;//如果比先前求出的小,说明是重要点
60         }
61         printf("Board %d have %d important blanks for %d chessmen.\n",_case++,count,ans);
62     }
63     return 0;
64 }
原文地址:https://www.cnblogs.com/wally/p/2991344.html