Codeforces 1103 C. Johnny Solving

Codeforces 1103 C. Johnny Solving

题目大意

有一张 \(n\) 个点 \(m\) 条边的简单无向图,每个点的度数至少为 \(3\) ,你需要构造出两种情况之一

  1. 一条长度至少为 \(\frac{n}{k}\) 的简单路径

  2. \(k\) 个大小大于 \(3\) 且不为 \(3\) 的倍数的简单环,且满足每个环中至少有一个点只属于这个环。

如果都构造不出来则输出 \(-1\)

解题思路

首先必定可以构造出来,\(-1\) 就是用来迷惑你的。

从无向图生成树的角度考虑,如果生成树的最大深度至少为 \(\frac{n}{k}\) ,那么直接输出简单路径,否则可以证明生成树一定有至少 \(k+1\) 个叶子。

假设叶子数量小于 \(k+1\) ,每一个叶子的深度最大为 \(\frac{n}{k}-1\),由于所有叶子到根的路径的并是这棵树,所以所有叶子的深度之和要大于 \(n\) ,矛盾。

事实上每一个叶子都可以构造出一个长度不为 \(3\) 的倍数的简单环,由于每个点度数 $\geq 3 $ ,那么每个叶子至少存在两条反祖边,假设叶子 \(u\) 对应的这两个祖先分别为 \(x, y\)

如果其中一个祖先满足 \(dep[x] \bmod 3 \neq 0\) ,那么 \(u\) 到这祖先就能形成一个合法环。

否则两个祖先都满足 \(\bmod 3 = 0\) 那么 \(x-y\) 之间的路径再加上 \(u\) 就能形成一个 \(\bmod 3 = 1\) 的合法环。

考虑每一个环都包含一个叶子,这个叶子显然满足在所有环里只出现一次。

code

/*program by mangoyang*/ 
#include<bits/stdc++.h>
#define inf ((ll)(1e17))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int N = 1000005;
pair<int, int> q[N];
vector<int> g[N], leaf;
int vis[N], dep[N], dd[N], ms[N], fa[N], n, m, k;
inline void dfs(int u){
	vis[u] = 1, dep[u] = 1; int tot = 0;
	for(int i = 0; i < (int) g[u].size(); i++){
		int v = g[u][i];-
		if(v == fa[u]) continue;
		if(!vis[v]){
			fa[v] = u, dd[v] = dd[u] + 1, dfs(v);
			if(dep[v] >= dep[u]) 
				dep[u] = dep[v] + 1, ms[u] = v;
			tot++;
		}
		else{
			if(!q[u].first) q[u].first = v;
			else if(!q[u].second) q[u].second = v;
		}
	}
	if(!tot) leaf.push_back(u);
}
inline void outpath(int u){
	printf("%d ", u);
	if(ms[u]) outpath(ms[u]);
}
inline void gao(int x, int y){
	if(dd[x] < dd[y]) swap(x, y);
	while(x != y) printf("%d ", x), x = fa[x];
	printf("%d ", y);
}
int main(){
	read(n), read(m), read(k);
	for(int i = 1, x, y; i <= m; i++){
		read(x), read(y);
		g[x].push_back(y), g[y].push_back(x);
	}
	dfs(1);
	if(dep[1] >= n / k){
		puts("PATH");
		cout << dep[1] << endl;
		return outpath(1), 0;
	}
	puts("CYCLES");
	for(int i = 0; i < k; i++){
		int u = leaf[i];
		int x = q[u].first, y = q[u].second;
		if((dd[u] - dd[x] + 1) % 3 != 0) 
            printf("%d\n", dd[u] - dd[x] + 1), gao(u, x), puts("");
		else if((dd[u] - dd[y] + 1) % 3 != 0) 
            printf("%d\n", dd[u] - dd[y] + 1), gao(u, y), puts("");
		else printf("%d\n", abs(dd[x] - dd[y]) + 2), gao(x, y), printf("%d\n", u); 
	}
}
posted @ 2019-03-03 16:34  Joyemang33  阅读(164)  评论(0编辑  收藏  举报