此題標難度2500,場內ac4人,因爲是一開始的cf,段位都不高就給的分低了。可能有2700分。
歐拉路徑好題
題意:給你一個無向圖,問能否輸出兩條路徑,使得遍歷所有邊。
思路:很顯然,一眼能想到歐拉路徑,但是兩條看似簡單,其實要想很多。
- m==1 此時輸出-1
- 只有一個聯通塊,那麼我們仔細想一下,當度數爲0,2,4的時候是可以的,0 和 2很顯然。但4怎麼搞,這是一個這道題比較難也比較亮的一點。我的做法是給兩個奇度加邊,然後輸出的時候隔離這個加邊。那麼我們來證明一下吧,無向圖的歐拉路徑只要滿足a. 聯通 b. 奇度爲0,和奇度爲2,此時可以。那麼我們輸出兩條路徑,等價於我們把4個奇度兩個相連變爲一個2奇度的圖,然後跑歐拉路徑,之後只要隔離這條邊就行了。
- 兩個聯通塊,每個塊度數爲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
*/