cf 36e Two Paths

此题标难度2500,场内ac4人,因为是一开始的cf,段位都不高就给的分低了。可能有2700分。
欧拉路径好题
题意:给你一个无向图,问能否输出两条路径,使得遍历所有边。
思路:很显然,一眼能想到欧拉路径,但是两条看似简单,其实要想很多。

  1. m==1 此时输出-1
  2. 只有一个联通块,那么我们仔细想一下,当度数为0,2,4的时候是可以的,0 和 2很显然。但4怎么搞,这是一个这道题比较难也比较亮的一点。我的做法是给两个奇度加边,然后输出的时候隔离这个加边。那么我们来证明一下吧,无向图的欧拉路径只要满足a. 联通 b. 奇度为0,和奇度为2,此时可以。那么我们输出两条路径,等价于我们把4个奇度两个相连变为一个2奇度的图,然后跑欧拉路径,之后只要隔离这条边就行了。
  3. 两个联通块,每个块度数为0,2时可以。
    有个大佬用图解的方法写出来了:https://www.luogu.org/blog/user56917/solution-cf36e
    我的代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1e4+5;
//vector<int>zz;
int head[maxn],deg[maxn],ans[maxn],vis[maxn],tot,sum,cnt,cnt2;
bool a[maxn];
struct edge{
    int v,nex;
    bool ok;
}e[maxn<<1];
void init(){
    forn(i,maxn) head[i] = -1;
    tot = 0;
}
void add(int u,int v){
    e[tot] = {v,head[u],0};
    head[u] = tot++;
}
void dfs(int u){
    vis[u] = cnt;
    //cerr<<"@!#!@ "<<u<<' '<<cnt<<'\n';
    for(int i = head[u];i!=-1;i = e[i].nex){
        int v = e[i].v;
        if(!vis[v]) dfs(v);
    }
}
void euler(int u){
    for(int i = head[u];i!=-1;i = e[i].nex){
        int v = e[i].v;
        if(e[i].ok) continue;
        e[i].ok = 1,e[i^1].ok = 1;
        euler(v);
        //cerr<<"asdas        "<<u<<' '<<v<<'\n';
        ans[++sum] = i+2>>1;
    }
    //zz.push_back(u);
}
int main(){
    IO;
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    init();
    int m;cin>>m;
    if(m==1) return cout<<-1<<'\n',0;
    forn(i,m){
        int u,v;cin>>u>>v;
        deg[u]++,deg[v]++;
        //cerr<<deg[u]<<' '<<deg[v]<<'\n';
        a[u] = a[v] = 1;
        add(u,v),add(v,u);
    }
    for1(i,maxn-5) if(!vis[i]&&a[i]) cnt++,dfs(i);
    if(cnt>2) return cout<<-1<<'\n',0; 
    if(cnt==1){
        cnt = 0;
        for1(i,maxn-5) if(deg[i]&1) cnt++; 
        if(cnt!=2&&cnt!=4&&cnt!=0) return cout<<-1<<'\n',0; 
        if(cnt==0){
            for1(i,maxn-5) if(a[i]) {
                euler(i);
                break;
            }
            cout<<m-1<<'\n';
            for(int i = m;i>1;i--) cout<<ans[i]<<' ';
            cout<<'\n';
            cout<<1<<'\n';
            cout<<ans[1]<<'\n';
        }else if(cnt==2){
            for1(i,maxn-5) if(deg[i]&1){
                euler(i);
                break;
            }
            cout<<m-1<<'\n';
            //cerr<<"!@#@!#  "<<sum<<' '<<m<<'\n';
            for(int i = m;i>1;i--) cout<<ans[i]<<' ';
            cout<<'\n';
            cout<<1<<'\n';
            cout<<ans[1]<<'\n';
        }else{
            vector<int>odd;
            for1(i,maxn-5) if(deg[i]&1) odd.push_back(i);
            add(odd[1],odd[2]); 
            add(odd[2],odd[1]);
            //cerr<<odd[0]<<'\n';
            euler(odd[0]);
            //cerr<<"!@##@!  "<<sum<<' '<<m<<'\n';
            //reverse(zz.begin(),zz.end());
            //for(auto &x:zz) cerr<<x<<' ';
           // cerr<<'\n';
            while(1){
                if(ans[sum]>m) break;
                sum--;
            }
            cout<<m+1-sum<<'\n';
            for(int i = m+1;i>sum;i--) cout<<ans[i]<<' ';
            sum--;
            cout<<'\n';
            cout<<sum<<'\n';
            for(int i = sum;i>=1;i--) cout<<ans[i]<<' ';
        }
        return 0;
    }
    //cerr<<"@!#!@# "<<'\n'; 
    cnt = 0;
    for1(i,maxn) if(deg[i]&1){
        //cerr<<"!@#!@# "<<i<<' '<<vis[i]<<'\n';
        if(vis[i]==1) cnt++;
        else cnt2++;
    }
    //cerr<<cnt<<' '<<cnt2<<'\n';
    if(cnt!=0&&cnt!=2) return cout<<-1<<'\n',0; 
    if(cnt2!=0&&cnt2!=2) return cout<<-1<<'\n',0;
    if(cnt==0){
        for1(i,maxn) if(vis[i]==1){
            euler(i);
            break;
        }
    }else{
        for1(i,maxn) if((deg[i]&1)&&vis[i]==1){
            euler(i);
            //cerr<<"@!#@# "<<i<<'\n';
            break;
        }
    }
    cout<<sum<<'\n';
    for(int i = sum;i>=1;i--) cout<<ans[i]<<' ';
    cout<<'\n';
    sum = 0;
    if(cnt2==0){
        for1(i,maxn) if(vis[i]==2){
            euler(i);
            break;
        }
    }else{
        for1(i,maxn) if((deg[i]&1)&&vis[i]==2){
            euler(i);
            break;
        }
    }
    cout<<sum<<'\n';
    for(int i = sum;i>=1;i--) cout<<ans[i]<<' ';
    cout<<'\n';
    return 0;
}
/*
9
1 2
2 3
3 4
4 5
5 2
4 6
6 7
7 8
8 6
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章