1325F - Ehab’s Last Theorem[思维+ d f s dfs dfs树]
time limit per test | memory limit per test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
Description:
It’s the year 5555. You have a graph, and you want to find a long cycle and a huge independent set, just because you can. But for now, let’s just stick with finding either.
Given a connected graph with n vertices, you can choose to either:
find an independent set that has exactly ⌈ n ⌉ \lceil \sqrt{n} \rceil ⌈n⌉ vertices.
find a simple cycle of length at least ⌈ n ⌉ \lceil \sqrt{n} \rceil ⌈n⌉.
An independent set is a set of vertices such that no two of them are connected by an edge. A simple cycle is a cycle that doesn’t contain any vertex twice. I have a proof you can always solve one of these problems, but it’s too long to fit this margin.
Input
The first line contains two integers n n n and m m m ( 5 ≤ n ≤ 1 0 5 , n − 1 ≤ m ≤ 2 × 1 0 5 ) (5≤n≤10^5, n−1≤m≤2 \times 10^5) (5≤n≤105,n−1≤m≤2×105) — the number of vertices and edges in the graph.
Each of the next m m m lines contains two space-separated integers u u u and v ( 1 ≤ u , v ≤ n ) v (1≤u,v≤n) v(1≤u,v≤n) that mean there’s an edge between vertices u u u and v v v. It’s guaranteed that the graph is connected and doesn’t contain any self-loops or multiple edges.
Output
If you choose to solve the first problem, then on the first line print “ 1 1 1”, followed by a line containing ⌈ n ⌉ \lceil \sqrt{n} \rceil ⌈n⌉ distinct integers not exceeding n n n, the vertices in the desired independent set.
If you, however, choose to solve the second problem, then on the first line print “ 2 2 2”, followed by a line containing one integer, c c c, representing the length of the found cycle, followed by a line containing c c c distinct integers integers not exceeding n n n, the vertices in the desired cycle, in the order they appear in the cycle.
One Example input
6 6
1 3
3 4
4 2
2 6
5 6
5 1
One Example output
1
1 6 4
One Example input
6 8
1 3
3 4
4 2
2 6
5 6
5 1
1 4
2 5
One Example output
2
4
1 5 2 4
Three Example input
5 4
1 2
1 3
2 4
2 5
Three Example output
1
3 4 5
分析:
题意:
给一个无向图,保证图连通且不包含自环和重边
要求输出以下两种其中一种
一:输出长度大于等于
⌈
n
⌉
\lceil \sqrt{n} \rceil
⌈n⌉的简单环
二:输出包含
⌈
n
⌉
\lceil \sqrt{n} \rceil
⌈n⌉个顶点的独立集
简单环:除开首尾以外,剩下的部分不会经过重复的点的环就叫做简单环
独立集:集合中任意两点互不相邻的点,即两两之间没有存在直接边连接
如果是第一种情况要先输出一个
"
1
"
"1"
"1"
如果是第二种情况则要先输出一个
"
2
"
"2"
"2"
做法:
第一种情况找环,利用
d
f
s
dfs
dfs树(下图源dls)
d
f
s
dfs
dfs向下搜索的时候如果遇到了环,那么当前这个点
u
u
u的深度一定会大于之前走过的那个点
v
v
v的深度
即环的大小为
d
e
p
[
u
]
−
d
e
p
[
v
]
+
1
dep[u] - dep[v] + 1
dep[u]−dep[v]+1,如果满足情况则可以输出
并且在搜索的时候记录每个点的前驱,这样最终找到的时候就可以输出路径
接下来令
d
=
⌈
n
⌉
d = \lceil \sqrt{n} \rceil
d=⌈n⌉(方便写)
如果没有环的话,那么一定会存在元素个数大于等于
d
d
d的独立集
原因是鸽巢定理
,也称抽屉定理
定理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。这一现象就是我们所说的“抽屉原理”。
没有长度大于等于
d
d
d的环,也就意味着任意距离为
d
−
1
d-1
d−1的两点,没有边连接
那么如果模
(
d
−
1
)
(d-1)
(d−1),这同模的这些顶点也必然没有边相互连接
又
⌈
n
⌉
≤
n
⌈
n
⌉
−
1
\lceil \sqrt{n} \rceil \leq \frac{n}{\lceil \sqrt{n} \rceil - 1}
⌈n⌉≤⌈n⌉−1n必然成立,根据上面的抽屉原理
因此统计每个点的深度
(
m
o
d
(
d
−
1
)
)
\pmod {(d-1)}
(mod(d−1))的个数
肯定存在某个模后的值的个数大于等于
d
d
d
然后输出即可
附上dls的视频(dlsnb! 尖叫)
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
int re() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -f; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x<<3)+(x<<1)+ch-'0'; ch = getchar();}
return x * f;
}
vector<int> ed[maxn]; // 存边
int dep[maxn]; // 记录深度
int pre[maxn]; // 记录前驱 方便输出
int cnt[1000]; // 记录 dep%(d-1)
bool flag; // 判断是否找到满足的环
int d; // 需要满足的长度
void dfs(int u) {
cnt[dep[u] % (d - 1)] += 1;
for(auto v : ed[u]) {
if(v == pre[u]) continue;
if(flag) return ;
if(dep[v] == -1) { // 还没走过
dep[v] = dep[u] + 1, pre[v] = u;
dfs(v);
}else if(dep[u] - dep[v] + 1 >= d) { // 找到环
printf("2\n%d\n", dep[u] - dep[v] + 1);
for(int i = u; i != pre[v]; i = pre[i]) // 走到v的时候
printf("%d%c", i, pre[i] == pre[v] ? '\n' : ' ');
flag = true;
}
}
}
int main() {
int n, m, u, v;
n = re(), m = re();
d = sqrt(n * 1.0), flag = false;
if(d * d != n) d += 1;
memset(cnt, 0, sizeof(cnt));
memset(pre, 0, sizeof(pre));
memset(dep, -1, sizeof(dep));
for(int i = 1; i <= m; ++i) {
u = re(), v = re();
ed[u].push_back(v), ed[v].push_back(u);
}
dep[1] = 0;
dfs(1);
if(flag) return 0;
printf("1\n");
for(int i = 0; i < d - 1; ++i) {
if(cnt[i] < d) continue;
int ans = d;
for(int j = 1; j <= n; ++j) {
if(dep[j] % (d - 1) == i) {
printf("%d%c", j, --ans ? ' ' : '\n');
if(!ans) return 0;
}
}
}
return 0;
}