1. 程式人生 > >Codeforces Round #375 (Div. 2) F. st-Spanning Tree

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