2200专项:F2. Spanning Tree with One Fixed Degree(图中找一棵树,节点1连d个点)

原题: http://codeforces.com/problemset/problem/1133/F2

题意: 给出一棵树,没有自环重边,从这棵树中扒出一棵树,节点1有d个连点。

解析:

分析将节点1和与之相连的边去掉后的图。

首先分析节点1的两个有连边的点p1、p2,如果p1和p2之间有一条不通过点1的路径。假设p1可以跑到p2,那么p2一定可以跑到p1,且p1可以跑到的其他点,p2都可以跑到。这个结论很重要。

将这些可以互相连通的点放入一个集合。设集合的数量为k。

  1. 如果k=d,那么刚刚好,直接跑每个集合即可;
  2. 如果k>d,说明点1不可能用d条边将所有点都连起来,输出NO;
  3. 如果k<d,那么说明我需要将某些集合拆成多个集合,来凑这个d;比方说点1连了p1和p2,而p1和p2属于一个集合。如果此时d=2,那么我就把p1和p2拆开。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define repp(i,a,b) for(register int i=a;i>=b;i--)
#define mmm(p) memset(p,0,sizeof p)
#define pill pair<int,int>
#define debug(i) printf("#%d\n",i)
#define F double
typedef long long LL;
LL read() {
    LL ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')
        last=ch,ch=getchar();
    while(ch>='0' && ch<='9')
        ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')
        ans=-ans;
    return ans;
}

const int maxn=2e5+5,maxm=4e5+5;
int head[maxn],to[maxm],nex[maxm],now;
void add(int a,int b){
    nex[++now]=head[a];head[a]=now;to[now]=b;
}

unordered_set<int>Set[maxn]; // 联通的点集
bool vis[maxn];
vector<int>set_id;           // 集合标号
bool link_one[maxn];         // 与1相连

void dfs(int p,int id){
    if(link_one[p])Set[id].insert(p);
    vis[p]=1;
    for(int i=head[p];i;i=nex[i]){
        int u=to[i];
        if(vis[u])continue;
        dfs(u,id);
    }
}

void prin(int p,int fa){     //k=d的情况
    vis[p]=1;
    printf("%d %d\n",p,fa);
    for(int i=head[p];i;i=nex[i]){
        int u=to[i];
        if(vis[u])continue;
        prin(u,p);
    }
}

void bfs(int id,int ct){    //k<d的情况
    ct++;
    queue<int>Q;
    unordered_set<int>::iterator it=Set[id].begin();
    while(ct--){
        int p=(*it);++it;
        vis[p]=1;
        Q.push(p);
        printf("%d %d\n",1,p);
    }
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        for(int i=head[p];i;i=nex[i]){
            int u=to[i];
            if(vis[u])continue;
            vis[u]=1;Q.push(u);
            printf("%d %d\n",p,u);
        }
    }
}

int main(){
    int n=read(),m=read(),d=read();
    rep(i,1,m){
        int a=read(),b=read();
        add(a,b);
        add(b,a);
    }
    int ct=0;
    for(int i=head[1];i;i=nex[i]){
        link_one[to[i]]=1;
        ct++;
    }
    if(ct<d)return 0*printf("NO\n");

    vis[1]=1;
    int set_num=0;
    for(int i=head[1];i;i=nex[i]){
        int u=to[i];
        if(vis[u])continue;
        set_num++;
        set_id.push_back(u);
        dfs(u,u);
    }
    if(set_num>d)return 0*printf("NO\n");
    printf("YES\n");
    
    if(set_num==d){
        memset(vis,0,sizeof(vis));
        vis[1]=1;
        for(int i=0;i<set_id.size();i++){
            prin(set_id[i],1);
        }return 0;
    }
    int need=d-set_num;
    int now=0;
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    while(need>0){
        int id=set_id[now++];
        int siz=Set[id].size();
        bfs(id,min(siz-1,need));
        need-=min(siz-1,need);
    }
    while(now<set_id.size()){
        bfs(set_id[now++],0);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88689741