2017 CCPC秦皇岛 D

考虑到对于一个联通块,最后一个加的点一定是度数最大的点,并且度数是联通块的siz-1。而把这个点删掉之后的图,因为每个点的度数同减一,依然满足上述性质。于是反过来想可以发现,若有解,则将最终度数从小到大依次加入图的方案一定是一组解。判断这种加点方式是否成立即可。用并查集维护联通性。

#include <bits/stdc++.h>
using namespace std;
const int maxn=105000;
vector<int>g[maxn], ans[maxn];
int n, m;
int fa[maxn], siz[maxn], id[maxn], degree[maxn];
bool vis[maxn];
bool cmp(int x, int y){
    return degree[x]<degree[y];
}
int f(int x){
    if(x==fa[x])return x;
    return fa[x]=f(fa[x]);
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        for(int i=1;i<=n;i++){
            g[i].clear();
            ans[i].clear();
            fa[i]=id[i]=i, siz[i]=1;
            degree[i]=0;
            vis[i]=false;
        }
        for(int i=1;i<=m;i++){
            int u, v;
            scanf("%d%d", &u, &v);
            degree[u]++, degree[v]++;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        sort(id+1, id+1+n, cmp);
        //for(int i=1;i<=n;i++)printf("%d%c", id[i], i==n?'\n':' ');
        bool ok=true;
        for(int i=1;i<=n;i++){
            int u=id[i];
            int sum=0;
            vis[u]=true;
            for(int j=0;j<g[u].size();j++){
                int v=g[u][j];
                if(!vis[v])continue;
                sum++;
                v=f(v);
                if(v==u)continue;
                ans[i].push_back(v);
                fa[v]=u;
                siz[u]+=siz[v];
            }
            if(siz[u]!=sum+1){
                ok=false;
                break;
            }
        }
        if(!ok)printf("No\n");
        else {
            printf("Yes\n");
            for(int i=1;i<=n;i++){
                printf("%d %d", id[i], (int)ans[i].size());
                for(int j=0;j<ans[i].size();j++){
                    printf(" %d", ans[i][j]);
                }
                printf("\n");
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/mrbird_to_fly/article/details/78423761
今日推荐