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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章