1. 程式人生 > 實用技巧 >F. Ehab's Last Theorem dfs樹!!!

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;
}