dfs樹是解決圖中帶環的利器。
前天CF的F題就是dfs樹,但是當時我沒有認真思考 覺着找到一個環過於困難 當時沒有想到 也沒理解dfs樹的意義。
對於一張無向圖求出一個dfs樹 這個樹有兩種邊 樹邊和非樹邊。
其中非樹邊連接的u v 他們一定具有祖先關系。
$注:這是一個很顯然 也十分重要的性質。
應用:CF1325F Ehab's Last Theorem
給出一張無向聯通圖 且不存在重邊 自環。定義\(m=\lceil sqrt(n)\rceil\)
求出圖中一個環S 滿足S是一個簡單環 且\(|S|\geq m\)
或者求出圖中一個independent set W 滿足 W=m
求環或者求獨立集 我們考慮一張無向圖 很難求出最大的獨立集 但是只是讓求出一個大小為m的獨立集。
考慮如何求環 dfs樹。但是求不了最大環 但是我們要的也不是最大。我們利用非樹邊判斷環的大小。
由於沒有重邊 自環 所以一個點連出w條非樹邊 那么顯然有大小為w+1的環。
如果所有點都沒有構成大小>=m的環 那說明每個點都最多有 m-2條非樹邊。
這個時候考慮最大獨立集 當前點我們加入到我們的集合中 然后其最多影響m-2個點。
把能影響的都給標記了 最后我們發現最多能選 \(\lceil \frac{n}{m-1}\rceil\)個點 可以證明這個東西>=m.證畢。
所以我們直接上dfs樹即可。值得注意的是 最后構造獨立集的時候 需要從葉子節點構造。
可以證明 這樣對其他節點的影響如上面的分析一樣。
const int MAXN=200010;
int n,m,len=1,w,top,flag,cc;
int vis[MAXN],s[MAXN],d[MAXN],mark[MAXN],q[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
inline void add(int x,int y)
{
ver[++len]=y;nex[len]=lin[x];lin[x]=len;
ver[++len]=x;nex[len]=lin[y];lin[y]=len;
}
inline void dfs(int x,int las)
{
if(flag)return;
vis[x]=1;s[++top]=x;
go(x)
{
if((i^1)==las)continue;
if(flag)break;
if(!vis[tn])
{
d[tn]=d[x]+1;
dfs(tn,i);
}
else if(d[x]-d[tn]+1>=w)
{
put(2);
put(d[x]-d[tn]+1);
int ww=d[x]-d[tn]+1;
while(ww)
{
printf("%d ",s[top]);
--top;--ww;
}
flag=1;
}
}
--top;
if(!mark[x])
{
q[++cc]=x;
go(x)mark[tn]=1;
}
}
int main()
{
freopen("1.in","r",stdin);
get(n);get(m);
rep(1,m,i)add(read(),read());
w=(int)ceil(sqrt(n*1.0));
//put(w);
dfs(1,-1);
if(flag)return 0;
put(1);rep(1,w,i)printf("%d ",q[i]);
return 0;
}
當然dfs樹還有應用 如上次我寫了一道bzoj 的電壓 那道題是真的比較妙 dfs樹上差分。最后證明的是 其他環都是無效的 有dfs樹上的環即可。
一道例題:LINK:2115 Wc2011 Xor
給出一張有向無環圖 求出1~n的一條路徑使得其xor和最大。路徑可以經過同一條邊同一個點 不過這樣的路徑的價值被計算相應次數。
顯然一條路徑出現兩次相當於沒出現。如何求這樣的路徑。可以考慮線性基求最大值。