[CF780E]Underground Lab

\(\text{Problem}:\)Underground Lab

\(\text{Solution}:\)

观察到 \(\lceil \frac{2n}{k} \rceil \times k \geq 2n\),而我们对于一个无向连通图进行 \(DFS\),将第一次遍历和回溯到的点都加入路径中,这条路径长度 \(len \leq 2n\),原因是每条边被经过 \(2\) 次,而对于这条边的两个端点,如果其中一个点的度为 \(1\),那么它有可能只被加入路径 \(1\) 次。

所以我们无论如何都可以经过所有点,只需要给每个人分配小于等于 \(\lceil \frac{2n}{k} \rceil\) 个点即可。特殊的,如果这条路径已经被分配完了却还有人剩余,这说明所有点都已经被遍历过了,那么让这个人站在 \(1\) 节点就行了,特判一下即可。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=400010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,K,book[N];
int g[N*10+5]; int cnt;
int head[N],maxE; struct Edge { int nxt,to; }e[N<<1];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
void DFS(int x)
{
	book[x]=1;
	g[++cnt]=x;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(book[v]) continue;
		DFS(v), g[++cnt]=x;
	}
}
signed main()
{
	n=read(), m=read(), K=read();
	for(ri int i=1;i<=m;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v), Add(v,u);
	}
	int Mx=(n*2-1)/K+1;
	DFS(1);
	for(ri int i=1;i<=K;i++)
	{
		int now=min(cnt,Mx);
		if(!now) { puts("1 1"); continue; }
		printf("%lld",now);
		for(ri int j=1;j<=now;j++)
		{
			printf(" %lld",g[cnt--]);
		}
		puts("");
	}
	return 0;
}
posted @ 2021-02-22 14:02  zkdxl  阅读(52)  评论(1编辑  收藏  举报