F. Ehab's Last Theorem dfs樹!!!
阿新 • • 發佈:2020-07-28
題目大意:
給你一個圖,構造一個序列,這個序列有兩種構造方法,任選其一構造即可。
- 找到一個獨立集,獨立集包含 \(\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 \frac{n}{ \left \lceil \ \sqrt[]{n}\ \right \rceil - 1 } \right \rceil $ >= \(\left \lceil \ \sqrt[]{n}\ \right \rceil\),所以肯定可以找到滿足條件的獨立集。
接下來解釋一下為什麼是最多呢?因為對於一個節點來說,它的子節點之間肯定不會有邊相連,所以如果我選中的值往上走走不了\(\left \lceil \ \sqrt[]{n}\ \right \rceil\)
#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;
}