POJ 1523 SPF (割点 点双连通分量)
生活随笔
收集整理的這篇文章主要介紹了
POJ 1523 SPF (割点 点双连通分量)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:求出割點以及除去割點后的連通分量的數量(附帶求出了點雙連通分量(塊)) [求割點]對圖深度優先搜索,定義DFS(u)為u在搜索樹(以下簡稱為樹)中被遍歷到的次序號。定義Low(u)為u或u的子樹中能通過非父子邊追溯到的最早的節點,即DFS序號最小的節點。根據定義,則有:Low(u)=Min {DFS(u),DFS(v)|(u,v)為后向邊(等價于DFS(v)<DFS(u)且v不為u的父親節點),Low(v)|(u,v)為樹枝邊} [條件]一個頂點u是割點,當且僅當滿足(1) u為樹根,且u有多于一個子樹。或(2) u不為樹根,且滿足存在(u,v)為樹枝邊(即u為v在搜索樹中的父親),使得DFS(u)<=Low(v)。 [除去點后的連通分量的]:對于(1)的割點,數量為子樹的數量;(2)的數量就是滿足條件的v的個數+1(它的父親節點). [求點雙連通分支]對于點雙連通分支,實際上在求割點的過程中就能順便把每個點雙連通分支求出。建立一個棧,存儲當前雙連通分支,在搜索圖時,每找到一條樹枝邊或后向邊,就把這條邊加入棧中。如果遇到某時滿足DFS(u)<=Low(v),說明u是一個割點,同時把邊從棧頂一個個取出,直到遇到了邊(u,v),取出的這些邊與其關聯的點,組成一個點雙連通分支。割點可以屬于多個點雙連通分支,其余點和每條邊只屬于且屬于一個點雙連通分支。 ?
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MID(x,y) ((x+y)>>1)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;const int MAXE = 1000005;
const int MAXV = 1005;
struct node{int u, v;int next;
}arc[MAXE];
int cnt, head[MAXV];
void init(){cnt = 0;mem(head, -1);
}
void add(int u, int v){arc[cnt].u = u;arc[cnt].v = v;arc[cnt].next = head[u];head[u] = cnt++;arc[cnt].u = v;arc[cnt].v = u;arc[cnt].next = head[v];head[v] = cnt++;return ;
}int id, dfn[MAXV], low[MAXV]; //時間戳
int bcc_num; //點雙聯通分量標號
vector bcc[MAXV]; //因為割點可以屬于多個雙聯通分量,所以用數組存儲每個雙聯通分量的節點而不是用標號數組表示每個節點所屬的雙聯通分量
stack st; //棧中存著樹枝邊或后向邊
int res[MAXV]; //本題所求答案,即割點連接的雙聯通分量個數,樹根是子樹個數,非樹根是子樹個數+1.
void addbcc(int bcc_num, int u){for (int i = 0; i < (int)bcc[bcc_num].size(); i ++){if (bcc[bcc_num][i] == u)return ;}bcc[bcc_num].push_back(u);
}
void tarjan(int u, int father){dfn[u] = low[u] = ++id;int child = 0;for (int i = head[u]; i != -1; i = arc[i].next){int v = arc[i].v;if (v == father) continue;if (dfn[v] < dfn[u]){ //避免正向邊st.push(i);if (!dfn[v]){ //樹枝邊child ++; //注意這里統計兒子節點時不要寫在if外面tarjan(v, u);low[u] = min(low[u], low[v]);if (dfn[u] <= low[v]){bcc_num ++;res[u] ++; //非樹根節點連接的雙聯通分量個數while(!st.empty()){int su = arc[st.top()].u;int sv = arc[st.top()].v;st.pop();addbcc(bcc_num, su);addbcc(bcc_num, sv);if((su == u && sv == v) || (su == v && sv == u)){break;}}}}else{ //后向邊low[u] = min(low[u], dfn[v]);}}}//統計割點連接的雙聯通分量個數if (father == 0){if (child >= 2){ //樹根大于一個子樹才是割點res[u] = child;}elseres[u] = 0;}else if (res[u] > 0) //非樹根除了子樹個數還要加上父親節點res[u] ++;
}
void solve(){id = bcc_num = 0;mem(dfn, 0);mem(low, 0);mem(res, 0);while(!st.empty())st.pop();tarjan(1, 0);
}
int main(){int u, v;int t = 0;while(scanf("%d", &u) == 1){init();++ t;if (u == 0)break;if (t > 1)puts("");scanf("%d", &v);add(u, v);while(scanf("%d", &u) == 1){if (u == 0)break;scanf("%d", &v);add(u, v);}solve();bool flag = 0;printf("Network #%d\n", t);for (int i = 1; i <= MAXV; i ++){if (res[i] > 0){printf(" SPF node %d leaves %d subnets\n", i, res[i]);flag = 1;}}if (!flag){puts(" No SPF nodes");}}return 0;
}
轉載于:https://www.cnblogs.com/AbandonZHANG/archive/2013/05/30/4114026.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的POJ 1523 SPF (割点 点双连通分量)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SSL证书配置指南
- 下一篇: android ndk 架构,NDK需要