標籤:main problem 理解 strong static from div using out
求割點
DFS搜尋樹:用DFS對圖進行遍曆時,按照遍曆次序的不同,我們可以得到一棵DFS搜尋樹。
樹邊:(稱為父子邊),可理解為在DFS過程中訪問未訪問節點時所經過的邊。
回邊:(返祖邊、後向邊),可理解為在DFS過程中遇到已訪問節點時所經過的邊。
該演算法是R.Tarjan發明的。觀察DFS搜尋樹,我們可以發現有兩類節點可以成為割點:
- 對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u為割點;
- 對非葉子節點u(非根節點),若其有一子樹的節點均沒有指向u的祖先節點的回邊,說明刪除u之後,根結點與u的子樹的節點不再連通;則節點u為割點。
http://cogs.pro/cogs/problem/problem.php?pid=8
#include<cstdio>#include<algorithm>using namespace std;struct Edge{ int to,next;}edge[10005];int fi[105],top,low[105],fa[105],dfn[105],kid[105];bool vis[105],cut[105];void add_edge(int from,int to){ edge[++top].next=fi[from],fi[from]=top,edge[top].to=to; edge[++top].next=fi[to],fi[to]=top,edge[top].to=from;}void dfs(int x){ //記錄dfs遍曆次序 static int counter = 0; dfn[x]=low[x]=++counter; vis[x]=1; if(x==4) x=4; for(int to = fi[x];to;to=edge[to].next){ int v=edge[to].to; if(!vis[v]){//節點v未被訪問,則(u,v)為樹邊 fa[v]=x;kid[x]++; dfs(v); low[x]=min(low[x],low[v]); if(low[v]>=dfn[x])cut[x]=1; } else if(v!=fa[x]){//節點v已訪問,則(u,v)為回邊 low[x]=min(low[x],dfn[v]); } }}int main(){ freopen("gd.in","r",stdin); freopen("gd.out","w",stdout); int n,a,b,ans=0;scanf("%d",&n); while(~scanf("%d%d",&a,&b))add_edge(a,b); dfs(1); if(kid[1]<2)cut[1]=0; for(int i=1;i<=n;i++){ if(cut[i])ans++; } printf("%d\n",ans); for(int i=1;i<=n;i++){ if(cut[i])printf("%d\n",i); } return 0;}求橋
對於一條邊(u,v),u為祖先,如果v的所有子樹都沒有指向比v先遍曆到的點則(u,v)為橋
圖的聯通-割點和橋