Codeforces 9E Interesting Graph and Apples(并查集)

本文介绍了一个使用并查集算法解决特定图论问题的方法:如何通过添加最少数量的边使得图中所有点恰好构成一个环形结构。文章详细解释了算法流程,并给出了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

大致就是给你n个点,这n个点之间有m条边相连,问能不能再添加几条边,使这n个点刚好能围成一个圈.

因为是无向图,判断能否成一个圈,也就是一个始祖,所以用了并查集。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int mn=55;
int degree[mn];//记录顶点的度数
int n,m,ansop;
int father[mn];
struct node
{
    int u,v;
} op[6000];//记录添加的边
void  init()
{
    int i;
    for(i=1; i <=n ; i++)
        father[i] = i;
}
int find(int x)
{
    int r=x;
    while(r!=father[r])
        r=father[r];
    int i=x,j;
    while(i!=r)
    {
        j=father[i];
        father[i]=r;
        i=j;
    }
    return r;
}
void Union(int a,int b)
{
    int at =find(a);
    int bt= find(b);
    if(at==bt) return;
    else
        father[at] = father[bt];
}
bool ans()                           
{
    for(int i=1; i<=n; i++)
    {
        if(degree[i]<2)
        {
            for(int j=i+1; j<=n; j++)
                if(degree[j]<2&&find(i)!=find(j))
                {
                    Union(i,j);
                    op[ansop].u=i;
                    op[ansop].v=j;
                    ansop++;
                    degree[i]++;
                    degree[j]++;
                    break;
                }
            if(degree[i]<2)
            {
                for(int j=i+1; j<=n; j++)
                    if(degree[j]<2&&find(i)!=find(j))
                    {
                        Union(i,j);
                        op[ansop].u=i;
                        op[ansop].v=j;
                        ansop++;
                        degree[i]++;
                        degree[j]++;
                        break;
                    }
            }
        }
    }
    int cot=0;
    for(int i=1; i<=n; i++)
    {
        if(degree[i]!=1&&degree[i]!=2) return false;
        if(degree[i]==1) cot++;
    }
    if(cot==2) return true;
    else return false;
}
int main()
{
    int x,y;
    bool sign;
    bool flag;
    while(cin>>n>>m)
    {
        if(n==1&&m==0)                         //特判,当只有1个点和0跳边
        {
            cout<<"YES"<<endl<<"1"<<endl<<"1 1"<<endl;
            continue;
        }
        int tmp=0;
        sign=flag=0;
        init();
        ansop=0;
        memset(degree,0,sizeof(degree));
        while(m--)
        {
            cin>>x>>y;
            degree[x]++;
            degree[y]++;
            if(find(x)==find(y)) flag=1;//如果形成环,标记为1
            Union(x,y);
        }
        for(int i=1; i<=n; i++)      
            tmp=max(degree[i],tmp);
        if(tmp>2)                        //如果有度数大于2的,肯定是NO
        {
            cout<<"NO"<<endl;
            continue;
        }
        if(flag)                         //若有原图中有环,进行讨论
        {
            int t=find(1);
            for(int i=2; i<=n; i++)
            {
                if(t==find(i)&&degree[i]==2) continue;
                else
                {
                    sign=1;
                    break;
                }
            }
            if(!sign) cout<<"YES"<<endl<<"0"<<endl;
            else
                cout<<"NO"<<endl;
            continue;
        }
        if(ans())
        {
            int p[2],cot=0;
            for(int i=1; i<=n; i++)
                if(degree[i]==1) p[cot++]=i;
            op[ansop].u=p[0];
            op[ansop++].v=p[1];
            cout<<"YES"<<endl;
            cout<<ansop<<endl;
            for(int i=0; i<ansop; i++)
                cout<<op[i].u<<" "<<op[i].v<<endl;
        }
        else cout<<"NO"<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值