【2020.11.23提高組模擬】徒(walk) 題解
阿新 • • 發佈:2020-11-23
【2020.11.23提高組模擬】徒(walk) 題解
題目描述
給一個簡單連通無向圖,選一個點為起點,每次選一條沒有走過的邊走,若無則停止。問是否存在一個起點使得無論如何選擇,走出來的路徑一定是尤拉路。
\(T\le 10,n\le100000,m\le200000\)
Solution
這是一道結論題。
首先要存在尤拉路,才可能存在那樣的一個起點。這個先特判。
接下來有一個結論。
結論:
對於所有點度都是偶數的圖,若存在一個點被所有環經過,則存在那樣的起點且就是被所有環穿過的點,否則不行
對於有兩個點度是奇數的圖,若存在一個奇度點被所有環經過,才存在,否則不存在。
證明:
對於所有點度都是偶數的圖,若存在一個點被所有點經過,我們設這個點為起點,假設我們已經走了一些歐拉回路並且有一些點沒有走,那麼由於歐拉回路中的所有點的度數為偶數,可以發現剩下邊組成的圖的點的度數還是偶數,那麼剩下的邊組成的圖中一定是尤拉圖集合,其中一定有環。又因為起點就是在環上的,所以可以直接走,一定有解。
若不存在一個點被所有的環穿過,則一定可以構造出一種不符合要求的方案。
奇數的類似證明。
而判斷一個點是否在所有環上只需要刪除這個點以及其邊,圖若變成森林(找不到環),則這個點是合法的。這樣是\(O(n^2)\)的。
考慮當點度數都是偶數時貪心,發現起點一定是度數最大的點,因此可以一遍找環即可。
Code
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<set> #include<queue> #include<vector> #define IL inline #define re register #define LL long long #define ULL unsigned long long #ifdef TH #define debug printf("Now is %d\n",__LINE__); #else #define debug #endif using namespace std; template<class T>inline void read(T&x) { char ch=getchar(); int fu; while(!isdigit(ch)&&ch!='-') ch=getchar(); if(ch=='-') fu=-1,ch=getchar(); x=ch-'0';ch=getchar(); while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} x*=fu; } inline int read() { int x=0,fu=1; char ch=getchar(); while(!isdigit(ch)&&ch!='-') ch=getchar(); if(ch=='-') fu=-1,ch=getchar(); x=ch-'0';ch=getchar(); while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*fu; } int G[55]; template<class T>inline void write(T x) { int g=0; if(x<0) x=-x,putchar('-'); do{G[++g]=x%10;x/=10;}while(x); for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n'); } int q; int n,m; int head[400010],nxt[400010],ver[400010]; bool book[400010],unexist[400010]; int degree[100010]; int cnt; void insert(int x,int y) { nxt[++cnt]=head[x]; ver[cnt]=y; head[x]=cnt; nxt[++cnt]=head[y]; ver[cnt]=x; head[y]=cnt; degree[x]++; degree[y]++; } void init() { memset(head,0,sizeof(nxt)); memset(degree,0,sizeof(degree)); cnt=1; } bool dfs(int x,int fa) { if(book[x]) return 1; book[x]=1; for(re int i=head[x];i;i=nxt[i]) { if(unexist[i]||ver[i]==fa) continue; if(dfs(ver[i],x)) return 1; } return 0; } bool work(int s) { memset(book,0,sizeof(book)); memset(unexist,0,sizeof(unexist)); for(int i=head[s];i;i=nxt[i]) unexist[i]=unexist[i^1]=1; for(int i=1;i<=n;i++) { if(i==s||book[i]) continue; if(dfs(i,i)) return 0; } return 1; } int main() { freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); q=read(); while(q--) { init(); n=read(); m=read(); for(re int i=1;i<=m;i++) insert(read(),read()); int flag=0; for(int i=1;i<=n&&flag<=2;i++) if(degree[i]&1) flag++; if(flag!=0&&flag!=2) { cout<<"NO"<<endl; continue; } if(!flag) { re int s,sd=0; for(re int i=1;i<=n;i++) if(sd<degree[i]) sd=degree[i],s=i; if(work(s)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } else { re bool flag2=0; for(re int i=1;i<=n&&!flag2;i++) { if(degree[i]&1) { if(work(i)) flag2=1; } } if(flag2) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } return 0; }
End
寫程式碼的時候沒帶腦子。
沒了。