Codeforces Round #375 (Div. 2) F. st-Spanning Tree

传送门:Codeforces Round #375 (Div. 2) F. st-Spanning Tree

题意: 
给你n个点,m条边,有两个给定的点S,T以及它们在生成树中最大的度数 
求能否构造出一棵树,使得这两个点的度数满足要求

思路: 
求出不使用与S,T有关的边构成的联通块 
这些联通块与S,T有三种联通情况 
1.只与S相连 
2.只与T相连 
3.与S和T均相连 
记录一下已经使用的边的数量就可以了

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
struct Edge{
    int from,to;
}e[N];
vector<Edge>tmp,ans,mp[N];
int f[N],flag[N];

int find(int x){
    return f[x]==x ? x:f[x]=find(f[x]);
}

int main(){
    int n,m,s,t,ds,dt,degree_s=0,degree_t=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)   f[i]=i;
    for(int i=1;i<=m;i++)
        scanf("%d%d",&e[i].from,&e[i].to);
    scanf("%d%d%d%d",&s,&t,&ds,&dt);
    //构造出与S,T无关的若干个联通块
    for(int i=1;i<=m;i++){
        if(e[i].from==s||e[i].to==s||e[i].from==t||e[i].to==t)
            tmp.push_back(e[i]);
        else{
            int x=find(e[i].from),y=find(e[i].to);
            if(x!=y)    f[x]=y,ans.push_back(e[i]);
        }
    }
    bool Sta=false;//标记是否有S-T这条边
    for(int i=0;i<tmp.size();i++){
        if(tmp[i].to==s||tmp[i].to==s||tmp[i].to==t||tmp[i].to==t)
            swap(tmp[i].from,tmp[i].to);
        int x=find(tmp[i].from),y=find(tmp[i].to);
        if(x+y==s+t)
            Sta=true;
        else if(x==s)
            flag[y]|=1,mp[y].push_back(tmp[i]);
        else if(y==s)
            flag[x]|=1,mp[x].push_back(tmp[i]);
        else if(x==t)
            flag[y]|=2,mp[y].push_back(tmp[i]);
        else if(y==t)
            flag[x]|=2,mp[x].push_back(tmp[i]);
    }
    for(int i=1;i<=n;i++){
        if(flag[i]==1){ //只与S相连
            degree_s++;
            ans.push_back(mp[i][0]);
        }
        else if(flag[i]==2){//只与T相连
            degree_t++;
            ans.push_back(mp[i][0]);
        }
    }
    bool Flag=false;
    for(int i=1;i<=n;i++)
        if(flag[i]==3){
            if(Flag==false){
                int cnt=0;
                for(int j=0;j<mp[i].size();j++){
                    if(mp[i][j].from==s&&(cnt&1)==0)
                        ans.push_back(mp[i][j]),cnt|=1;
                    else if(mp[i][j].from==t&&(cnt&2)==0)
                        ans.push_back(mp[i][j]),cnt|=2;
                }
                degree_s++,degree_t++;
                Flag=true;
            }
            else{
                int st=ds-degree_s < dt-degree_t ? t:s;
                for(int j=0;j<mp[i].size();j++)
                    if(mp[i][j].from==st){
                        ans.push_back(mp[i][j]);
                        break;
                    }
                st==t ? ++degree_t:++degree_s;
            }
        }
    if(Flag==false&&Sta){
        degree_s++,degree_t++;
        ans.push_back((Edge){s,t});
    }
    if(degree_s<=ds&&degree_t<=dt&&ans.size()==n-1){
        printf("Yes\n");
        for(int i=0;i<ans.size();i++)
            printf("%d %d\n",ans[i].from,ans[i].to);
    }
    else
        printf("No\n");
    return 0;
}
--------------------- 
作者:_zidaoziyan 
来源:CSDN 
原文:https://blog.csdn.net/acm_fighting/article/details/52735228?utm_source=copy 

猜你喜欢

转载自blog.csdn.net/c_czl/article/details/83021039
今日推荐