POJ 1523 SPF 割點與橋的判斷演算法-Tarjan
阿新 • • 發佈:2019-01-26
題目連結:
題意:
問一個連通的網路中有多少個關節點,這些關節點分別能把網路分成幾部分
題解:
Tarjan 演算法模板題
順序遍歷整個圖,可以得到一棵生成樹:
樹邊:可理解為在DFS過程中訪問未訪問節點時所經過的邊,也稱為父子邊
回邊:可理解為在DFS過程中遇到已訪問節點時所經過的邊,也稱為返祖邊、後向邊
對根節點u,若其有兩棵或兩棵以上的子樹,則該根結點u為割點;
對非葉子節點u(非根節點),若其子樹的節點均沒有指向u的祖先節點的回邊,說明刪除u之後,根結點與u的子樹的節點不再連通;則節點u為割點。
// 當(u,v)為樹邊且low[v]>dfn[u]時,表示v節點只能通過該邊(u,v)與u連通,那麼(u,v)即為割邊。
用一個數組儲存每個節點的子樹個數即可
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define maxn 1050 using namespace std; int dfn[maxn],low[maxn]; //dfs序 和子樹連線的最小節點 int vis[maxn]; vector<int>edge[maxn]; int child[maxn]; int num,son; void init() { memset(vis,0,sizeof(vis)); memset(child,0,sizeof(child)); vis[1]=1; num=0; son=0; } void Tarjan(int u) { dfn[u]=low[u]=++num; vis[u]=1; for(int i=0; i<edge[u].size(); i++) { int v=edge[u][i]; if(!vis[v]) { Tarjan(v); low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]) //得到子樹 { if(u!=1) child[u]++; else son++; } } else low[u]=min(low[u],dfn[v]); } } int main() { // freopen("in.txt","r",stdin); int a,b; int Case=1; while(1) { while(scanf("%d",&a)&&a) { scanf("%d",&b); edge[a].push_back(b); edge[b].push_back(a); } init(); Tarjan(1); // for(int i=1;i<=5;i++) // cout<<dfn[i]<<" "<<low[i]<<endl; if(Case>1) cout<<endl; printf("Network #%d\n",Case++); int flag=1; child[1]=son-1; for(int i=1; i<=1000; i++) if(child[i]>0) { flag=0; printf(" SPF node %d leaves %d subnets\n",i,child[i]+1); } if(flag) cout<<" No SPF nodes"<<endl; for(int i=1; i<=1000; i++) edge[i].clear(); scanf("%d",&a); if(a==0) break; scanf("%d",&b); edge[a].push_back(b); edge[b].push_back(a); } return 0; }