Codeforces 1103 C. Johnny Solving
题目大意:
有一张 (n) 个点 (m) 条边的简单无向图,每个点的度数至少为 (3) ,你需要构造出两种情况之一
-
一条长度至少为 (frac{n}{k}) 的简单路径
-
(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] mod 3 eq 0) ,那么 (u) 到这祖先就能形成一个合法环。
否则两个祖先都满足 (mod 3 = 0) 那么 (x-y) 之间的路径再加上 (u) 就能形成一个 (mod 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
", dd[u] - dd[x] + 1), gao(u, x), puts("");
else if((dd[u] - dd[y] + 1) % 3 != 0)
printf("%d
", dd[u] - dd[y] + 1), gao(u, y), puts("");
else printf("%d
", abs(dd[x] - dd[y]) + 2), gao(x, y), printf("%d
", u);
}
}