zoukankan      html  css  js  c++  java
  • 【生成树趣题】CF723F st-Spanning Tree

    题目传送门

    题意:

    给定一个n个点m条边的无向联通图,没有重边和自环。给定s和t,求一棵生成树,使得s,t的度数不超过ds,dt。若有解,输出“Yes”和方案(多组方案输出任意一组),若无解,输出“No”。

    数据范围:

    2 ≤ n ≤ 200 000

    分析:

    首先,可以把边分成两类:一类是端点含s或t的,另一类是和s,t没有任何关系的。第二类边可以随便乱连,而第一类边不可以。

    所以,就先把第二类边乱连,随便连,反正没有边权连就是了,用一个并查集,相当于搞一个生成树森林出来,这样我们就有了很多很多块集合(相当于被缩成一个点,要注意细节)和s,t两个点。

    集合中只与s,t的其中一个点有边的,只能连那个边,否则就不联通了。一边连一边判断s,t的度数,如果超过了就判定无解。

    集合中和s,t都有边相连的,选一个和s,t都连一条边,这样可以使s,t联通的同时尽量最小化度数。(s,t直接相连,度数各增加1,某一个集合再和s,t中的一个相连,s,t中的一个度数会增加1)

    剩下的和s,t都有边相连的集合,随便连s,t都可以。(如果一个点的度数被连完了,就连另外那个)

    最后,如果没有和s,t都有边相连的集合,那么此时s,t还没有被连起来,那么还要在s,t之间直接连一条边。

    注意还要判断它是不是一棵生成树的形态(边数为n-1)

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<iomanip>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<queue>
      7 using namespace std;
      8 #define ll long long
      9 #define N 200005
     10 int n,m,s,t,ds,dt;
     11 vector<int>G[N];
     12 vector<pair<int,int> >ans;
     13 int f[N];//并查集
     14 int ls[N],lt[N];//编号为i的集合通过ls[i]/lt[i]和s/t相连 
     15 inline int rd()
     16 {
     17     int f=1,x=0;char c=getchar();
     18     while(c<'0'||'9'<c){if(c=='-')f=-f;c=getchar();}
     19     while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
     20     return f*x;
     21 }
     22 int Find(int x)
     23 {
     24     if(f[x]==x) return x;
     25     return f[x]=Find(f[x]);
     26 }
     27 bool Union(int u,int v)
     28 {
     29     int x=Find(u),y=Find(v);
     30     if(x==y) return false;
     31     if(x<y) f[y]=x;
     32     else f[x]=y;
     33     return true; 
     34 }
     35 void Init()
     36 {
     37     for(int i=1;i<=n;i++)
     38         f[i]=i;
     39 } 
     40 int main()
     41 {
     42     n=rd(),m=rd();
     43     for(int i=1;i<=m;i++)
     44     {
     45         int u=rd(),v=rd();
     46         G[u].push_back(v);
     47         G[v].push_back(u);
     48     }
     49     s=rd(),t=rd(),ds=rd(),dt=rd();
     50     Init();
     51     //乱连不含s,t的边 
     52     for(int u=1;u<=n;u++)
     53     {
     54         if(u==s||u==t) continue;
     55         for(int i=0;i<G[u].size();i++)
     56         {
     57             int v=G[u][i];
     58             if(v==s||v==t) continue;
     59             if(Union(u,v)) ans.push_back(make_pair(u,v));
     60         }
     61     }
     62     //处理集合的哪些边和s,t相连的情况 
     63     for(int i=0;i<G[s].size();i++)
     64         if(G[s][i]!=t)
     65         {
     66             int x=Find(G[s][i]);
     67             ls[x]=G[s][i];
     68         }
     69     for(int i=0;i<G[t].size();i++)
     70         if(G[t][i]!=s)
     71         {
     72             int x=Find(G[t][i]);
     73             lt[x]=G[t][i];
     74         }
     75     //处理只和s,t中的一个相连的集合 
     76     for(int i=1;i<=n;i++)
     77     {
     78         if(ls[i]&&!lt[i])
     79         {
     80             ds--;
     81             Union(s,i);
     82             ans.push_back(make_pair(s,ls[i]));
     83         }
     84         else if(!ls[i]&&lt[i])
     85         {
     86             dt--;
     87             Union(t,i);
     88             ans.push_back(make_pair(t,lt[i]));
     89         }
     90         if(ds<0||dt<0)
     91         {
     92             puts("No");
     93             return 0;
     94         }
     95     }
     96     //处理和s,t都相连的集合 第一个会和s,t都连 s,t连通之后就只会连一个 
     97     for(int i=1;i<=n;i++)
     98         if(ls[i]&&lt[i])
     99         {
    100             if(ds&&Union(s,i))
    101             {/*短路运算符 Union不能写在前面 或者也可以用find()判断 Union写在里面*/
    102                 ds--;
    103                 ans.push_back(make_pair(s,ls[i]));
    104             }
    105             if(dt&&Union(t,i))
    106             {
    107                 dt--;
    108                 ans.push_back(make_pair(t,lt[i]));
    109             }
    110             if(Find(s)!=Find(i)||Find(t)!=Find(i)) //说明前面没有办法连 度数都用完了 
    111             {
    112                 puts("No");
    113                 return 0;
    114             }
    115         }
    116     if(Find(s)!=Find(t))//s,t还没有连通
    117     {
    118         bool f=0;
    119         for(int i=0;i<G[s].size();i++)
    120             if(G[s][i]==t)
    121             {
    122                 f=1;
    123                 break;
    124             }
    125         if(ds&&dt&&f)
    126             ans.push_back(make_pair(s,t));
    127         if(!f)
    128         {
    129             puts("No");
    130             return 0;
    131         }
    132     }
    133     if(ans.size()!=n-1)
    134     {//满足是一棵生成树 
    135         puts("No");
    136         return 0;
    137     }
    138     puts("Yes");
    139     for(int i=0;i<ans.size();i++)
    140         printf("%d %d
    ",ans[i].first,ans[i].second);
    141     return 0;
    142 }
    Code
  • 相关阅读:
    git简单使用命令
    localStorage的用法
    CSS3 进阶
    ASP.NET应用程序与页面生命周期
    IT专业人士如何更有效的学习专业知识
    jsonp跨域原理解析
    sql注入原理
    ajax跨域调用
    aspx、ashx以及cs的关系,viewState
    Js处理json数据
  • 原文地址:https://www.cnblogs.com/lyttt/p/11772931.html
Copyright © 2011-2022 走看看