CF1103C Johnny Solving
题目大意:
给出一张无重边的无向图(保证每个点度数大于等于 $3$ )和一个限制 $k$ ,需要你构造以下两种情况中的一种:
1. 找出一条路径长度为 $\frac{n}{k}$ 。
2. 找出 $k$ 个环,使得每个环的长度大于 $3$ 而且不是 $3$ 的倍数,并且要求保证每个环中至少有一个点在这 $k$ 个环里只出现一次。
思路:
考虑先建出一棵 $dfs$ 树,这时对于这棵树如果最长链长度大于 $\frac{n}{k}$ 那么就直接输出这条链,否则意味着每条链深度都小于 $\frac{n}{k}$ 。
那么这棵树至少有 $k$ 个叶子节点。
因为每一个节点度数大于等于 $3$ ,所以至少会有两条返祖边向上,假设连向 $a,b$ 两个节点,如果叶子节点分别和 $a,b$ 构成的环都恰好是 $3$ 的倍数,那么 $a,b$ 之间的链连上叶子节点构成的环就必然不为 $3$ 的倍数。这样对于 $\geq k$ 个叶子节点都能找到一个合法的环,输出任意 $k$ 个即可。
以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=3e5+5,M=5e5+5; bool vis[N]; int q[N],tot,fa[N]; int n,m,k,head[N],ne[M<<1],to[M<<1],cnt,d[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il void ins(int x,int y){ ne[++cnt]=head[x]; head[x]=cnt;to[cnt]=y; } il void dfs(int x){ vis[x]=1; if(d[x]>=(n+k-1)/k){ puts("PATH");printf("%d\n",d[x]); while(x)printf("%d ",x),x=fa[x]; exit(0); } bool pd=0; for(int i=head[x];i;i=ne[i]){ if(fa[x]==to[i]||vis[to[i]])continue; fa[to[i]]=x;d[to[i]]=d[x]+1;pd=1; dfs(to[i]); } if(!pd)q[++tot]=x; } int main() { n=read();m=read();k=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); ins(x,y);ins(y,x); } d[1]=1;dfs(1); puts("CYCLES"); for(int j=1;j<=k;j++){ int x=q[j],y=0,z=0; for(int i=head[x];i;i=ne[i]){ if(fa[x]==to[i])continue; if(!y)y=to[i];else z=to[i]; } int res=d[x]-d[y]+1; if(res%3){ printf("%d\n",res); while(x!=y){ printf("%d ",x);x=fa[x]; } printf("%d\n",y);continue; } res=d[x]-d[z]+1; if(res%3){ printf("%d\n",res); while(x!=z){ printf("%d ",x);x=fa[x]; } printf("%d\n",z);continue; } if(d[y]<d[z])swap(y,z); res=d[y]-d[z]+2; printf("%d\n",res); while(y!=z){ printf("%d ",y);y=fa[y]; } printf("%d %d\n",z,x); } return 0; }