[Codeforces Round #628]1325F - Ehab's Last Theorem[思维+dfs树]

6 篇文章 0 订阅
4 篇文章 0 订阅

1325F - Ehab’s Last Theorem[思维+ d f s dfs dfs]

time limit per testmemory limit per testinputoutput
1 seconds256 megabytesstandard inputstandard 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) (5n105,n1m2×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(1u,vn) 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 d1的两点,没有边连接
那么如果模 ( d − 1 ) (d-1) (d1),这同模的这些顶点也必然没有边相互连接
⌈ 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(d1))的个数
肯定存在某个模后的值的个数大于等于 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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值