F. Ehab's Last Theorem dfs树!!!

F. Ehab's Last Theorem

题目大意:

给你一个图,构造一个序列,这个序列有两种构造方法,任选其一构造即可。

  • 找到一个独立集,独立集包含 \(\left \lceil \ \sqrt[]{n}\ \right \rceil\) 个点。
  • 找到一个简单环,这个环上的点至少 \(\left \lceil \ \sqrt[]{n}\ \right \rceil\) 个,且按照环的顺序输出序列。

如果是第一种,则第一行先输出1,第二行输出这个序列,如果是第二种,则先输出2,再输出序列。

题解:

首先建一棵 \(dfs\) 树, \(dfs\) 树有一个性质就是:

每一个节点只会连向它的后代节点,或者说每一个回边都是后代连向他的祖先节点
\(dfs\) 树构建完之后,对于一个节点,它的子节点之间是不会有边相连的。

知道这个性质之后,我们可以尝试去找简单环,这个在一棵树上还是很好找的。

  • 对这棵树进行 \(dfs\) 如果出现回边,那就说明构成了一个简单环,就判断这个简单环的节点数是不是大于\(\left \lceil \ \sqrt[]{n}\ \right \rceil\) ,大于则可以之间输出答案。

  • 如果没有找到满足条件的简单环,那肯定可以找到一个满足条件的独立集,这是为什么呢?

    因为没有两个点之间的深度大于等于 \(\left \lceil \ \sqrt[]{n}\ \right \rceil - 1\) 的环,所以剩下的两个节点之间的深度肯定是小于等于 \(\left \lceil \ \sqrt[]{n}\ \right \rceil - 2\) 的,所以我们选完一个节点之后,最多会删除 \(\left \lceil \ \sqrt[]{n}\ \right \rceil - 1\) 个点 ,

    $ \left \lceil \frac{n}{ \left \lceil \ \sqrt[]{n}\ \right \rceil - 1 } \right \rceil $ >= \(\left \lceil \ \sqrt[]{n}\ \right \rceil\),所以肯定可以找到满足条件的独立集。

    接下来解释一下为什么是最多呢?因为对于一个节点来说,它的子节点之间肯定不会有边相连,所以如果我选中的值往上走走不了\(\left \lceil \ \sqrt[]{n}\ \right \rceil\) ,则不需要删\(\left \lceil \ \sqrt[]{n}\ \right \rceil - 1\) 这么多的节点数。

#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
int head[maxn],cnt;
struct node{
    int v,nxt;
    node(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[maxn];
void add(int u,int v){
    e[++cnt]=node(v,head[u]);
    head[u]=cnt;
    e[++cnt]=node(u,head[v]);
    head[v]=cnt;
}
int n,m,tot=0;
int dep[maxn],fa[maxn],ver[maxn];
void dfs(int u){
    ver[++tot]=u;
    dep[u]=dep[fa[u]]+1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fa[u]) continue;
        if(!dep[v]){
            fa[v]=u;
            dfs(v);
        }
        else{
            long long  l=dep[u]-dep[v]+1;
            if(l*l>=n){
                printf("2\n%d\n",l);
                int x=u;
                while(x!=v){
                    printf("%d ",x);
                    x=fa[x];
                }
                printf("%d\n",v);
                exit(0);
            }
        }
    }
}
bool vis[maxn];
int main(){
    cnt=0;
    scanf("%d%d",&n,&m);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    dfs(1);
    int l=1;
    for(;l*l<n;l++);
    int cur=l;
    printf("1\n");
    for(int i=n;i>=1;i--){
        int u=ver[i];
        if(vis[u]) continue;
        l--;
        printf("%d%c",u,l?' ':'\n');
        if(!l) break;
        for(int i=1;i<=cur-1;i++){
            vis[u]=1;
            u=fa[u];
        }
    }
    return 0;
}
posted @ 2020-07-28 21:31  EchoZQN  阅读(77)  评论(0编辑  收藏  举报