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] \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);
}
}
|
请发表评论