codeforces#36E Two Paths DFS

本文介绍了一种用于解决复杂图分割问题的高效算法,该算法通过判断图的有效连通块数来确定是否存在可行的分割方案,并进一步探讨了不同情况下的分割策略。算法涉及图论基本概念和欧拉通路的寻找,适用于需要将大型图分解为不相交路径的实际场景。

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

题目大意:给定一张n=10000,m<=10000的图,要求将这张图分割成两条不相交、不重复的路径,输出任意一组方案或无解

蛮水的一道题- -
首先m=1一定无解
然后判断有效点的连通块数,若3则无解
若连通块数量为2,则这两条路一定是每个连通块中的一条欧拉通路
若连通块的数量为1,讨论:
若度数为奇数的点>4,无解
若度数为奇数的点2,求出一条欧拉通路后拆成两段
若度数为奇数的点为4,则选择两个度数为奇数的点连一条新边,求出欧拉通路后从新边处断开即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 10100
using namespace std;
struct abcd{
    int to,num,next;
    bool flag;
}table[M<<1];
int head[M],tot=1;
int n=10000,m,a[2],degree[M];
int stack[M],top;
void Add(int x,int y,int z)
{
    degree[y]++;
    table[++tot].to=y;
    table[tot].num=z;
    table[tot].next=head[x];
    head[x]=tot;
}
namespace Union_Find_Set{
    int fa[M],rank[M];
    int Find(int x)
    {
        if(!fa[x]||fa[x]==x)
            return fa[x]=x;
        return fa[x]=Find(fa[x]);
    }
    void Union(int x,int y)
    {
        x=Find(x);y=Find(y);
        if(x==y) return ;
        if(rank[x]>rank[y])
            swap(x,y);
        if(rank[x]==rank[y])
            rank[y]++;
        fa[x]=y;
    }
}
void DFS(int x)
{
    int i;
    for(i=head[x];i;i=head[x])
    {
        head[x]=table[head[x]].next;
        if(table[i].flag)
            continue;
        table[i^1].flag=true;
        DFS(table[i].to);
        stack[++top]=table[i].num;
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    using namespace Union_Find_Set;
    int i,x,y;
    cin>>m;
    if(m==1)
    {
        cout<<-1<<endl;
        return 0;
    }
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y,i);Add(y,x,i);
        Union(x,y);
    }
    for(i=1;i<=n;i++)
        if(head[i])
        {
            if(!a[0])
                a[0]=i;
            else if(Find(i)!=Find(a[0]))
            {
                if(!a[1])
                    a[1]=i;
                else if(Find(i)!=Find(a[1]))
                    return cout<<-1<<endl,0;
            }
        }
    if(a[1])
    {
        int cnt[2]={0,0};
        int st[2]={a[0],a[1]};
        for(i=1;i<=n;i++)
            if(degree[i]&1)
            {
                cnt[Find(i)==Find(a[1])]++;
                st[Find(i)==Find(a[1])]=i;
            }
        if(cnt[0]>2||cnt[1]>2)
            return cout<<-1<<endl,0;
        DFS(st[0]);
        cout<<top<<endl;
        while(top)
            printf("%d%c",stack[top],top==1?'\n':' '),top--;
        DFS(st[1]);
        cout<<top<<endl;
        while(top)
            printf("%d%c",stack[top],top==1?'\n':' '),top--;
    }
    else
    {
        int st[4]={0,0,0,0};
        for(i=1;i<=n;i++)
            if(degree[i]&1)
            {
                if(!st[0])
                    st[0]=i;
                else if(!st[1])
                    st[1]=i;
                else if(!st[2])
                    st[2]=i;
                else if(!st[3])
                    st[3]=i;
                else
                    return cout<<-1<<endl,0;
            }
        if(!st[0])
        {
            DFS(a[0]);
            cout<<1<<'\n'<<stack[top--]<<endl;
            cout<<top<<endl;
            while(top)
                printf("%d%c",stack[top],top==1?'\n':' '),top--;
        }
        else if(!st[2])
        {
            DFS(st[0]);
            cout<<1<<'\n'<<stack[top--]<<endl;
            cout<<top<<endl;
            while(top)
                printf("%d%c",stack[top],top==1?'\n':' '),top--;
        }
        else
        {
            Add(st[0],st[1],m+1);
            Add(st[1],st[0],m+1);
            DFS(st[2]);
            for(i=1;i<=top;i++)
                if(stack[i]==m+1)
                    break;
            cout<<top-i<<endl;
            while(top>i)
                printf("%d%c",stack[top],top==i+1?'\n':' '),top--;
            top--;
            cout<<top<<endl;
            while(top)
                printf("%d%c",stack[top],top==1?'\n':' '),top--;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值