HDU 4687 Boke and Tsukkomi (一般图最大匹配)【带花树】

<题目链接>

题目大意:

给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的。

解题分析:

所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义。那怎样判断该匹配是否在最大匹配中呢?我们可以枚举每一对匹配,然后对其进行取消其匹配关系,对其余的匹配跑一遍最大匹配,如果是原始最大匹配-1,说明这对匹配关系在最大匹配关系中。需要注意的是,删除匹配关系的时候,不经要将该边的匹配关系删除,还需将所有点与这两点之间的匹配关系删除(即相当于删除这两点)。

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 using namespace std;
  9 #define MAXN 310
 10 #define CLR(a,b) memset(a,b,sizeof(a))
 11 deque<int> Q;
 12 //g[i][j]存放关系图:i,j是否有边,match[i]存放i所匹配的点
 13 bool g[MAXN][MAXN],inque[MAXN],inblossom[MAXN];
 14 int match[MAXN],pre[MAXN],base[MAXN];
 15  
 16 //找公共祖先
 17 int findancestor(int u,int v)
 18 {
 19     bool inpath[MAXN]={false};
 20     while(1)
 21     {
 22         u=base[u];
 23         inpath[u]=true;
 24         if(match[u]==-1)break;
 25         u=pre[match[u]];
 26     }
 27     while(1)
 28     {
 29         v=base[v];
 30         if(inpath[v])return v;
 31         v=pre[match[v]];
 32     }
 33 }
 34  
 35 //压缩花
 36 void reset(int u,int anc)
 37 {
 38     while(u!=anc)
 39     {
 40         int v=match[u];
 41         inblossom[base[u]]=1;
 42         inblossom[base[v]]=1;
 43         v=pre[v];
 44         if(base[v]!=anc)pre[v]=match[u];
 45         u=v;
 46     }
 47 }
 48  
 49 void contract(int u,int v,int n)
 50 {
 51     int anc=findancestor(u,v);
 52     CLR(inblossom,0);
 53     reset(u,anc);reset(v,anc);
 54     if(base[u]!=anc)pre[u]=v;
 55     if(base[v]!=anc)pre[v]=u;
 56     for(int i=1;i<=n;i++)
 57         if(inblossom[base[i]])
 58         {
 59             base[i]=anc;
 60             if(!inque[i])
 61             {
 62                 Q.push_back(i);
 63                 inque[i]=1;
 64             }
 65         }
 66 }
 67  
 68 bool dfs(int S,int n)
 69 {
 70     for(int i=0;i<=n;i++)pre[i]=-1,inque[i]=0,base[i]=i;
 71     Q.clear();Q.push_back(S);inque[S]=1;
 72     while(!Q.empty())
 73     {
 74         int u=Q.front();Q.pop_front();
 75         for(int v=1;v<=n;v++)
 76         {
 77             if(g[u][v]&&base[v]!=base[u]&&match[u]!=v)
 78             {
 79                 if(v==S||(match[v]!=-1&&pre[match[v]]!=-1))contract(u,v,n);
 80                 else if(pre[v]==-1)
 81                 {
 82                     pre[v]=u;
 83                     if(match[v]!=-1)Q.push_back(match[v]),inque[match[v]]=1;
 84                     else
 85                     {
 86                         u=v;
 87                         while(u!=-1)
 88                         {
 89                             v=pre[u];
 90                             int w=match[v];
 91                             match[u]=v;
 92                             match[v]=u;
 93                             u=w;
 94                         }
 95                         return true;
 96                     }
 97                 }
 98             }
 99         }
100     }
101     return false;
102 }
103  
104 int solve(int n)   
105 {
106     CLR(match,-1);
107     int ans=0;
108     for(int i=1;i<=n;i++)
109         if(match[i]==-1&&dfs(i,n))
110             ans++;
111     return ans;
112 }
113 /*--  以上为带花树求一般图最大匹配的模板   --*/
114 bool vis[200];
115 int a[200],b[200];
116 int main() {
117     int n , m;
118     while(scanf("%d%d",&n,&m) != EOF) {
119         CLR(g,false);CLR(vis,false);
120        for(int i = 1; i <= m; i++) {
121            scanf("%d%d",&a[i],&b[i]);
122            g[a[i]][b[i]] = g[b[i]][a[i]] = true;
123        }
124        int ans = solve(n);
125        vector<int> vec;
126        for(int i = 1; i <= m; i++) {   //枚举不进行匹配边
127            int x = a[i]  , y = b[i];
128            CLR(g,false);     //清空匹配关系,接下来进行重置 
129            for(int j = 1; j <= m; j++) if(i!=j){
130                int tmp1 = a[j] , tmp2 = b[j];
131                if(tmp1==x||tmp1==y||tmp2==x||tmp2==y)continue;   //为什么是将所有包含这两点之间匹配关系的全部(即删除点)清除 ??? 
132                g[tmp1][tmp2] = g[tmp2][tmp1] = true;
133            }
134            int tmp = solve(n);
135            if(tmp != ans - 1) {   //如果删除这条边后,最大匹配数不是原始值-1,说明这条边不在最大匹配中 
136                    vec.push_back(i);
137            }
138        }      
139        printf("%d\n",vec.size());
140        if(vec.size()>0) {
141            printf("%d",vec[0]);
142            for(int i = 1; i < vec.size(); i++) {
143                printf(" %d",vec[i]);
144            }
145        }
146        puts("");
147     }
148     return 0;
149 }

2018-11-19

猜你喜欢

转载自www.cnblogs.com/00isok/p/9986666.html