/* ID: linjd821 LANG: C++ TASK: Street Directions */ //此程序通过pku 1515 http://acm.pku.edu.cn/JudgeOnline/problem?id=1515 //求桥程序,首先假设无向图是连通的,参考《图算法:C语言实现》英文版 P108 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <assert.h> #include <ctype.h> #include <map> #include <string> #include <set> #include <bitset> #include <utility> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <iostream> #include <fstream> #include <list> using namespace std; #define BRIDGE 1 int N, M, E; const int MAXN = 1000+5; const int MAXM = MAXN*MAXN/10; struct Edge { int next, ed; bool type; }edge[MAXM]; int head[MAXN]; //d[i] is the DFS_Number of the Node i //h[i] = max(h[j]) (There is edge between i and j) //DN is the DFS_Number int h[MAXN], d[MAXN], DN; void add_edge(int u, int v) { edge[E].next = head[u]; edge[E].ed = v; edge[E].type = 0; head[u] = E++; edge[E].next = head[v]; edge[E].ed = u; edge[E].type = 0; head[v] = E++; } //This recursive bridge_dfs function get the bridges in a graph. //the h array keeps track of the highest preorder number that can //be reached from vertex by a sequence of tree edges, followed by one back edge //e为树边下标(father[t]-->t) void bridge_dfs(int t, int e) { int i; h[t] = d[t] = DN--; for(i = head[t]; i != -1; i = edge[i].next) { int ed = edge[i].ed; //ed点还未到达过 if(d[ed] == 0) { bridge_dfs(ed, i^1); if(h[t] < h[ed]) h[t] = h[ed]; if(h[ed] == d[ed]) { edge[i].type = edge[i^1].type = BRIDGE; //puts("find"); } } //边i是后向边 else if(i != e && h[t] < d[ed]) h[t] = d[ed]; } } void Find_Bridge() { //DFS_Number = N DN = N; memset(d, 0, sizeof(d)); memset(h, 0, sizeof(h)); bridge_dfs(1, -1); } /* ID: linjd821 LANG: C++ TASK: NetWork */ /*此代码通过pku1144 network http://acm.pku.edu.cn/JudgeOnline/problem?id=1144 此代码参考《算法设计技巧与分析》英文版 p264 */ //前提假设图是连通的 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <assert.h> #include <ctype.h> #include <map> #include <string> #include <set> #include <bitset> #include <utility> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <iostream> #include <fstream> #include <list> using namespace std; const int MAXN = 100+5; const int MAXM = MAXN*MAXN; struct Edge { int next, ed; }edge[MAXM]; int head[MAXN]; int N, M, E; //store the articulation point(割点) //vector<int>ap; int ap[MAXN], aplen; //During the travesal we maintain two arrays with each v∈V: //d[i]is DFS_Number of node i during the DFS(from DN to 1), //h[i]is the max DFS_Number of node i can reach except its father node in the DFS Tree //DN is initial to N(the number of nodes) /* The articulation points are determined as follows 1: The root is an articulation point if and only if it has two or more children in the depth-first tree 2: A vertex v other than the root is an articulation point if and only if v has a child w wei h[w] <= d[v] */ int h[MAXN], d[MAXN], DN, root_degree; void add_edge(int u, int v) { edge[E].ed = v; edge[E].next = head[u]; head[u] = E++; edge[E].ed = u; edge[E].next = head[v]; head[v] = E++; } void Init() { int i, j, k; char c; E = 0; memset(head, -1, sizeof(head)); while(scanf("%d", &j) && j) { while(scanf("%d%c", &k, &c)) { add_edge(j, k); if(c == '/n') break; } } } void atp_dfs(int t, int father) { int i; bool tag = false; d[t] = h[t] = DN--; for(i = head[t]; i != -1; i = edge[i].next) { int ed = edge[i].ed; if(d[ed] == 0) { atp_dfs(ed, t); if(t == 1) { root_degree++; //condition 1 if(root_degree == 2) tag = true; } //condition 2 else { if(h[t] < h[ed]) h[t] = h[ed]; if(h[ed] <= d[t]) tag = true; } } else if(ed != father && d[ed] > h[t]) h[t] = d[ed]; } //if(tag == true) ap.push_back(t); //if(tag == true) ap[aplen++] = t; if(tag == true) aplen++; } void Find_Articulation_Points() { memset(d, 0, sizeof(d)); memset(h, 0, sizeof(h)); DN = N; root_degree = 0; aplen = 0; //ap.clear(); atp_dfs(1, -1); } int main() { int i, j, k; //freopen("network.in", "r", stdin); //freopen("network.out", "w", stdout); while(scanf("%d", &N) && N) { Init(); Find_Articulation_Points(); //sort(ap, ap+aplen); //for(i = 0; i < aplen; i++) //printf("%d/n", ap[i]); printf("%d/n", aplen); } return 0; } /* ID: linjd821 LANG: C++ TASK: knight */ /******************************************************************************* 输入:边数组edge,链接表头数组head,节点数N,边数M 输出:二连通分量数DN,每个连通分量的其中一点构成的数组p *******************************************************************************/ /* 没有割点的图叫2-连通图,亦称做块, G中成块的极大子图叫做G的块。 把每个块收缩成一个点,就得到一棵树, 它的边就是桥。 双连通分量是边的集合,所以一条边算法是最小的双连通分量 */ const int MAXN = 1000+5; const int MAXM = 1000*1000+5; struct Edge { int next; int ed; //标记该边属于哪个连通块 int bc; }edge[MAXM]; int head[MAXN]; //每个二连通分量存一个点,p[i]表示第i个二连通分量有个点下标为p[i] int p[MAXN]; int N, M; //以下变量用于求二连通分量,以及保存相关的数据 //含义与强连通的分量里的三个变量相同 int d[MAXN], h[MAXN], DN, stk[MAXM/10], top, CN; void bcc_dfs(int t, int e) { int i; d[t] = h[t] = DN--; stk[top++] = t; //printf("t = %d, CN = %d/n", t, CN); for(i = head[t]; i != -1; i = edge[i].next) { //此边已删 if(edge[i].bc != -1) continue; //将每条边进栈两次(按两个不同方向)负表示是边的下标 stk[top++] = -i; //edge[i].ed is not the parent of t if(i != e) { if(d[edge[i].ed] == 0) { bcc_dfs(edge[i].ed, i^1); //t和edge[i].ed在剩下的途中不连通 if(h[edge[i].ed] <= d[t]) { p[++CN] = t; while(1) { if(stk[top-1] <= 0) { edge[-stk[top-1]].bc = CN; edge[(-stk[top-1])^1].bc = CN; } top--; if(-stk[top] == i) break; } //t是可能是连通分支的一部分,当然也有可能是其他连通分支的一部分 } if(h[t] < h[edge[i].ed]) h[t] = h[edge[i].ed]; } else if(h[t] < d[edge[i].ed]) h[t] = d[edge[i].ed]; } } } void Find_BCC() { int i; DN = N; CN = 0; memset(h, 0, sizeof(h)); memset(d, 0, sizeof(d)); top = 0; for(i = 1; i <= N; i++) { if(d[i] == 0) bcc_dfs(i, -1); } }