【2020.11.23提高组模拟】徒(walk) 题解
【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
写代码的时候没带脑子。
没了。