• 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
  • 相关阅读:
    viewport的target density
    iframe 文本编辑器
    201671010115 201620172《Java程序设计》第二周Java心得
    201671010115 201620172《Java程序设计》第四周Java心得
    201671010115 201620172《Java程序设计》对Java这门新课程的看法
    201671010115 201620172《Java程序设计》第三周Java心得
    201671010115 201620172《Java程序设计》第五周学习心得
    201671010115 201620172《Java程序设计》第六—七周Java学习心得
    《怎么样成为一个高手》观后感
    个人作业
  • 原文地址:https://www.cnblogs.com/liutianrui/p/13291923.html
Copyright © 2020-2023  润新知