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

F. Ehab's Last Theorem

题目大意:

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

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

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

题解:

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

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

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

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

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

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

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

    接下来解释一下为什么是最多呢?因为对于一个节点来说,它的子节点之间肯定不会有边相连,所以如果我选中的值往上走走不了(left lceil sqrt[]{n} ight ceil) ,则不需要删(left lceil sqrt[]{n} ight ceil - 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
%d
",l);
                int x=u;
                while(x!=v){
                    printf("%d ",x);
                    x=fa[x];
                }
                printf("%d
",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
");
    for(int i=n;i>=1;i--){
        int u=ver[i];
        if(vis[u]) continue;
        l--;
        printf("%d%c",u,l?' ':'
');
        if(!l) break;
        for(int i=1;i<=cur-1;i++){
            vis[u]=1;
            u=fa[u];
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/13394009.html