codeforces CF36E Two Paths 欧拉回路

$ \rightarrow $ 戳我进CF原题

E. Two Paths

time limit per test: 2 seconds
memory limit per test: 64 megabytes
input: input.txt
output: output.txt

 
Once archaeologists found $ m $ mysterious papers, each of which had a pair of integers written on them.
Ancient people were known to like writing down the indexes of the roads they walked along,
as « $ a \quad b $ » or « $ b \quad a $ » , where $ a,b $ are the indexes of two different cities joint by the road .
It is also known that the mysterious papers are pages of two travel journals
(those days a new journal was written for every new journey).
 
During one journey the traveler could walk along one and the same road several times in one or several directions
but in that case he wrote a new entry for each time in his journal. Besides,
the archaeologists think that the direction the traveler took on a road had no effect upon the entry:
the entry that looks like « $ a \quad b $ » could refer to the road from $ a $ to $ b $ as well as to the road from $ b $ to $ a $ .
 
The archaeologists want to put the pages in the right order and reconstruct the two travel paths but unfortunately,
they are bad at programming. That’s where you come in. Go help them!
 

Input

The first input line contains integer $ m (1 \le m \le 10000) $.
Each of the following m lines describes one paper. Each description consists of two integers $ a,b ( 1\le a,b \le 10000,a \not= b) $ .
 

Output

In the first line output the number $ L_i $ . That is the length of the first path, i.e. the amount of papers in its description.
In the following line output $ L_1 $ space-separated numbers — the indexes of the papers that describe the first path.
In the third and fourth lines output similarly the length of the second path $ L_2 $ and the path itself.
Both paths must contain at least one road, i.e. condition $ L_1>0 $ and $ L_2>0 $ must be met.
The papers are numbered from $ 1 $ to $ m $ according to the order of their appearance in the input file.
The numbers should be output in the order in which the traveler passed the corresponding roads.
If the answer is not unique, output any.
 
If it’s impossible to find such two paths, output «-1».
 
Don’t forget that each paper should be used exactly once, i.e $ L_1+L_2=m $ .
 

Examples

input1
 2
 4 5
 4 3 
output1
 1
 2
 1
 1

input2
 1
 1 2
output2
 -1

 

题目大意

  • 在无向图中找到两条路径,一共经过每条边恰好一次。

  • $ n,m \le 10000 $

 

题解

  • 连通块个数 $ >2 $ ,无解

  • 某个连通块奇度数点 $ >4 $ 个,无解

  • 连通块个数 $ =2 $ 并且其中一个连通块奇度数点 $ =4 $ 个,无解

  • 连通块个数 $ =1 $,奇度点个数 $ =4 $,在两个奇度点之间加一条虚边,求欧拉路,再断开

  • 其他情况,直接求欧拉路或欧拉回路

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 10005
struct edge{ int v,id,nxt; }e[maxn<<1];
int head[maxn],tot=1;
void add(int u,int v,int num){
    e[++tot].v=v; e[tot].id=num; e[tot].nxt=head[u]; head[u]=tot; 
}
int m,cnt,deg[maxn];
vector<int>pr[maxn];
bool vis[maxn];
void dfs1(int u){
    vis[u]=1;
    if(deg[u]&1) pr[cnt].push_back(u);
    for(int i=head[u];i;i=e[i].nxt)
        if(!vis[e[i].v]) dfs1(e[i].v);
}
int cut,top,s[maxn];
bool used[maxn],pr4;
void dfs2(int u){
    for(int i=head[u];i;i=e[i].nxt)
        if(!used[e[i].id]){
            used[e[i].id]=1;
            dfs2(e[i].v);
            s[++top]=e[i].id;
            if(e[i].id==m&&pr4) cut=top; 
        }
}
int minu=maxn,cnt2st;
bool pot[maxn];
int main(){
    freopen("input.txt","r",stdin); 
    freopen("output.txt","w",stdout);
    scanf("%d",&m);
    for(int u,v,i=1;i<=m;++i){
        scanf("%d %d",&u,&v);
        pot[u]=pot[v]=1;
        minu=min(minu,min(u,v));
        ++deg[u]; ++deg[v];
        add(u,v,i); add(v,u,i); 
    }
    if(m==1){ puts("-1"); return 0; } 
    for(int i=1;i<=10000;++i)
        if(!vis[i]&&pot[i]){
            ++cnt;
            if(cnt>2){ puts("-1"); return 0; }
            if(pr4){ puts("-1"); return 0; }
            dfs1(i);
            if(pr[cnt].size()>4){ puts("-1"); return 0; }
            if(pr[cnt].size()==4){
                if(cnt>1){ puts("-1"); return 0; }
                pr4=1;
            }
            if(cnt==2&&pr[2].size()==0) cnt2st=i;
        }
    if(pr4){
        add(pr[1][0],pr[1][1],m+1);
        add(pr[1][1],pr[1][0],m+1);
        ++m;
        dfs2(pr[1][2]);
        if(top!=m){ puts("-1"); return 0; }
        printf("%d\n",cut-1);
        for(int i=1;i<cut;++i) printf("%d ",s[i]);
        printf("\n%d\n",m-cut);
        for(int i=cut+1;i<=m;++i) printf("%d ",s[i]);
    } else {
        if(pr[1].size()) dfs2(pr[1][0]);
        else dfs2(minu);
        if(cnt==2){
            cut=top;
            if(pr[2].size()) dfs2(pr[2][0]);
            else dfs2(cnt2st);
            if(top!=m){ puts("-1"); return 0; }
            printf("%d\n",cut);
            for(int i=1;i<=cut;++i) printf("%d ",s[i]);
            printf("\n%d\n",m-cut);
            for(int i=cut+1;i<=m;++i) printf("%d ",s[i]);
        } else {
            if(top!=m){ puts("-1"); return 0; }
            puts("1");
            printf("%d ",s[1]);
            printf("\n%d\n",m-1);
            for(int i=2;i<=m;++i) printf("%d ",s[i]);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/PotremZ/p/CF36E.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值