2020牛客暑期多校训练营(第一场)I 1or 2题解

题意:

给定一个无向图,问能否从中选出一些边构成新图,使得每个点的度数为di,1<=di<=2,可以输出Yes,否则输出No。n<=50,m<=100 100组数据

当时第一反应是网络流,发现不可行之后尝试分析性质,发现最终的图一定是由一些环和一些链构成,尝试搜索+剪枝无果,后来想把这道题转化为01方程是否有解的判断,发现不会……

我们不妨先把问题简化,如果所有点di都为1,那么这道题就是问这张图上的最大匹配是多少,直接套一般图上的完美匹配板子即可。

那么我们可以尝试将di=2的点拆开,让他们各自找一个点匹配。那么就会有这样一个问题,由一个点拆开的两个点可能正好和另外两个由一个点拆开的点相匹配。所以我们不能将原边照搬,应当加以限制。

我们可以将一条边 e 拆成两个点e e',e和这条边的端点x ( x' ) 连边,e' 和y  ( y' ) ,e e'之间连边。这时,如果e与e'匹配,说明我们不选择这条边,否则说明我们选择了这条边,(似乎有点网络流最小割的意思)

之后我们在这张图上跑一般图上的完美匹配,看匹配数是否为点数除2即可。

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<queue>
  8 #define N 306
  9 #define M 4005
 10 using namespace std;
 11 int n,m,D[N];
 12 int zz,a[N];
 13 struct ro{
 14     int to,next;
 15 }road[M];
 16 void build(int x,int y)
 17 {
 18     zz++;
 19     road[zz].to=y;
 20     road[zz].next=a[x];
 21     a[x]=zz;
 22 }
 23 int fa[N],bj[N],pre[N],to[N],cnt2;
 24 queue<int> q1;
 25 int find(int x)
 26 {
 27     if(fa[x]==x)return x;
 28     return fa[x]=find(fa[x]);
 29 }
 30 int cnt,dfn[N];
 31 int get_lca(int x,int y)
 32 {
 33     cnt++;
 34     x=find(x),y=find(y);
 35     while(dfn[x]!=cnt)
 36     {
 37         dfn[x]=cnt;
 38         x=find(pre[to[x]]);
 39         if(y) swap(x,y);
 40     }
 41     return x;
 42 }
 43 void work2(int x,int y,int z)
 44 {
 45     while(find(x)!=z)
 46     {
 47         pre[x]=y,y=to[x];
 48         if(bj[y]==2) bj[y]=1,q1.push(y);
 49         if(find(x)==x) fa[x]=z;
 50         if(find(y)==y) fa[y]=z;
 51         x=pre[y];
 52     }
 53 }
 54 bool bfs(int S)
 55 {
 56     for(int i=1;i<=n*2+m*2;i++)
 57     {
 58         fa[i]=i,bj[i]=pre[i]=0;
 59     }
 60     while(!q1.empty())q1.pop();
 61     q1.push(S);bj[S]=1;
 62     while(!q1.empty())
 63     {
 64         int x=q1.front();q1.pop();
 65         for(int i=a[x];i;i=road[i].next)
 66         {
 67             int y=road[i].to;
 68             if(find(y)==find(x)||bj[y]==2)continue;
 69             if(!bj[y])
 70             {
 71                 bj[y]=2,pre[y]=x;
 72                 if(!to[y])
 73                 {
 74                     for(int now=y,la;now!=0;now=la)
 75                     {
 76                         la=to[pre[now]],to[now]=pre[now],to[pre[now]]=now;
 77                     }
 78                     return 1;
 79                 }
 80                 bj[to[y]]=1;q1.push(to[y]);    
 81             }
 82             else
 83             {
 84                 int lca=get_lca(x,y);
 85                 work2(x,y,lca);
 86                 work2(y,x,lca);
 87             }
 88         }
 89     }
 90     return 0;
 91 }
 92 bool work()
 93 {
 94     memset(dfn,0,sizeof(dfn));
 95     cnt=0;
 96     memset(to,0,sizeof(to));
 97     for(int i=1;i<=n*2+m*2;i++)
 98     {
 99         if(!to[i]) bfs(i);
100     }
101     int ans=0;
102     for(int i=1;i<=n*2+m*2;i++) if(to[i]) ans++;
103     return ans==cnt2;
104 }
105 int deg[N];
106 int main()
107 {
108     while(~scanf("%d%d",&n,&m))
109     {
110         zz=0;
111         memset(a,0,sizeof(a));
112         cnt2=n;
113         for(int i=1;i<=n;i++)
114         {
115             scanf("%d",&D[i]);
116             if(D[i]==2)cnt2++;
117         }
118         memset(deg,0,sizeof(deg));
119         cnt2+=m*2;
120         for(int i=1;i<=m;i++)
121         {
122             int x,y;
123             scanf("%d%d",&x,&y);
124             deg[x]++,deg[y]++;
125             if(D[x]==2)
126             {
127                 build(x,2*n+i);
128                 build(x+n,2*n+i);
129                 build(2*n+i,x);
130                 build(2*n+i,x+n);
131             }
132             else
133             {
134                 build(x,2*n+i);
135                 build(2*n+i,x);
136             }
137             if(D[y]==2)
138             {
139                 build(2*n+m+i,y);
140                 build(2*n+m+i,y+n);
141                 build(y,2*n+m+i);
142                 build(y+n,2*n+m+i);
143             }
144             else
145             {
146                 build(y,2*n+m+i);
147                 build(2*n+m+i,y);
148             }
149             build(2*n+i,2*n+m+i);
150             build(2*n+m+i,2*n+i);
151         }
152         bool op=1;
153         for(int i=1;i<=n;i++)
154         {
155             if(deg[i]<D[i])
156             {
157                 op=0;
158             }
159         }
160         if(!op)
161         {
162             printf("No
");
163             continue;
164         }
165         if(work())printf("Yes
");
166         else printf("No
");
167     }
168     return 0;
169 }
170 /*
171 2 2
172 1 2 1
173 1 2 2
174 3
175 0 2
176 3 3
177 1 4
178 */
View Code
原文地址:https://www.cnblogs.com/liutianrui/p/13291923.html