codeforces1103C Johnny Solving

本文详细解析了Codeforces比赛中的C题解决方案,通过深入分析题目特点,提出了以1为根节点构建DFS树的方法,探讨了叶子节点与深度的关系,并给出了一种寻找满足条件路径或环的具体算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://codeforces.com/problemset/problem/1103/C

乱搞了一下午,TLE on 30,换一种方式 TLE on 35。。。

然后看了题解,看了一半,自己想,又wa了好久,最后还是把最后给看了。。。。

假设有c个叶子节点,设dep[1]=1,那么对于这c个叶子节点(dep[i1]+dep[i2]+...dep[ic])>=n,因为每个点都会被至少一条路径覆盖到,然后根节点1可能会被覆盖到多次。那么max{dep[i1],dep[i2]...dep[ic]}>=n/c,所以dfs树的叶子节点个数和深度是有关系的 。

所以以1位根节点建dfs树,如果深度>=n/k,直接记路径,不超过n/k,那么至少就会有k个叶子节点,对于每个叶子节点除了连向父亲的边,至少还有向上的两条边,所以会得到3个环,且至少有一个环的长度>3,设叶子节点为u,这两条边向上到的点为d1,d2,假设(dep[u]-dep[d1]+1)%3==0,(dep[u]-dep[d1]+1)%3==0,这两个圆就是不行的,但是从这两个式子我们发现dep[d1]%3==dep[d2]%3,那么对于d1...d2.u这个环的长度为(dep[d1]-dep[d2]+2)一定=2。所以这3个环必有一个符合条件。

由于无向图dfs树叶子节点互相没有到达,所以以每个叶子节点为第一个点就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=5e5+10;

int n,m,ans,cas,k,tot,cnt,up;
bool flag;
int a[maxl],du[maxl],dep[maxl],fa[maxl],leaf[maxl];
vector<int> e[maxl];
bool vis[maxl];
vector<int> b[maxl];

inline void dfs(int len,int u)
{
	vis[u]=true;a[len]=u;bool son=false;
	if(len==up)
	{
		ans=1;
		for(int i=1;i<=len;i++)
			b[1].push_back(a[i]);
		return;
	}
	for(int v:e[u])
	{
		if(vis[v] || v==fa[u])continue;
		dep[v]=dep[u]+1;fa[v]=u;son=true;
		dfs(len+1,v);
		if(ans)
			return;
	}
	if(!son)
		leaf[++tot]=u;
	a[len]=0;
}

inline void prework()
{
	scanf("%d%d%d",&n,&m,&k);
	int u,v;up=n/k+(n%k!=0);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);du[u]++;
		e[v].push_back(u);du[v]++;
	}
	ans=0;dep[1]=1;fa[1]=0;
	dfs(1,1);
} 

inline void mainwork()
{
	if(ans)
		return;
	ans=2;int d1,d2,u,d;
	for(int i=1;i<=k;i++)
	{
		d1=0;d2=0;u=leaf[i];
		for(int v:e[u])
		if(v!=fa[u])
		{
			if(!d1) d1=v;
			else{d2=v;break;}
		}
		if(dep[d1]<dep[d2])
			swap(d1,d2);
		if(dep[u]-dep[d1]+1>=3 && (dep[u]-dep[d1]+1)%3!=0)
		{
			d=u;
			while(d!=d1)
			{
				b[i].push_back(d);
				d=fa[d];
			}
			b[i].push_back(d1);
		}
		else if(dep[u]-dep[d2]+1>=3 && (dep[u]-dep[d2]+1)%3!=0)
		{
			d=u;
			while(d!=d2)
			{
				b[i].push_back(d);
				d=fa[d];
			}
			b[i].push_back(d2);
		}
		else
		{
			b[i].push_back(u);d=d1;
			while(d!=d2)
			{
				b[i].push_back(d);
				d=fa[d];
			}
			b[i].push_back(d2);
		}
	}
}

inline void print()
{
	if(!ans)
		puts("-1");
	else if(ans==1)
	{
		puts("PATH");
		printf("%d\n",up);
		for(int i=0;i<up;i++)
			printf("%d%c",b[1][i],(i==up-1)?'\n':' ');
	}
	else
	{
		puts("CYCLES");int l;
		for(int i=1;i<=k;i++)
		{
			l=b[i].size();
			printf("%d\n",l);
			for(int j=0;j<l;j++)
				printf("%d%c",b[i][j],(j==l-1)?'\n':' ');
		}
	}
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值