刘汝佳白书上面的一道题目:题意是给定一个联通分量,求出割顶以及双连通分量的个数,并且要求出安放安全井的种类数,也就是每个双连通分量中结点数(除开 割顶)个数相乘,对于有2个及以上割顶的双连通分量可以不用安放安全井。如果整个图就是一个双连通分量,那么需要安放两个安全井,种类数是n*(n-1)/2.
代码来自刘汝佳白书:
1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <climits> 5 #include <cstring> 6 #include <cstdlib> 7 #include <string> 8 #include <stack> 9 #include <map> 10 #include <cmath> 11 #include <vector> 12 #include <queue> 13 #include <algorithm> 14 #define esp 1e-6 15 #define pi acos(-1.0) 16 #define pb push_back 17 #define mp(a, b) make_pair((a), (b)) 18 #define in freopen("in.txt", "r", stdin); 19 #define out freopen("out.txt", "w", stdout); 20 #define print(a) printf("%d\n",(a)); 21 #define bug puts("********))))))"); 22 #define stop system("pause"); 23 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 24 #define pragma comment(linker, "/STACK:102400000, 102400000") 25 #define inf 0x0f0f0f0f 26 27 28 using namespace std; 29 typedef long long LL; 30 typedef vector<int> VI; 31 typedef pair<int, int> pii; 32 typedef vector<pii,int> VII; 33 typedef vector<int>:: iterator IT; 34 const int maxn = 50010; 35 struct Edge{ 36 int u, v; 37 Edge(int u, int v):u(u), v(v){} 38 }; 39 int pre[maxn], low[maxn], bccno[maxn], iscut[maxn], bcc_cnt, dfs_clock; 40 VI g[maxn], bcc[maxn]; 41 stack<Edge> S; 42 int dfs(int u, int fa) 43 { 44 int lowu = pre[u] = ++dfs_clock; 45 int child = 0; 46 for(int i = 0; i < g[u].size(); i++) 47 { 48 int v = g[u][i]; Edge e = Edge(u, v); 49 if(!pre[v]) 50 { 51 S.push(e); 52 child++; 53 int lowv = dfs(v, u); 54 lowu = min(lowu, lowv); 55 if(lowv >= pre[u]) 56 { 57 iscut[u] = 1; 58 bcc_cnt++; bcc[bcc_cnt].clear(); 59 for(;;) 60 { 61 Edge x = S.top(); S.pop(); 62 if(bccno[x.u] != bcc_cnt) {bccno[x.u] = bcc_cnt; bcc[bcc_cnt].pb(x.u);} 63 if(bccno[x.v] != bcc_cnt) {bccno[x.v] = bcc_cnt; bcc[bcc_cnt].pb(x.v);} 64 if(x.u == u && x.v == v) break; 65 } 66 } 67 } 68 else if(pre[v] < pre[u] && v!= fa) 69 { 70 S.push(e); 71 lowu = min(lowu, pre[v]); 72 } 73 } 74 if(child == 1 && fa < 0) iscut[u] = 0; 75 return low[u] = lowu; 76 } 77 void find_bcc(int n) 78 { 79 memset(iscut, 0, sizeof(iscut)); 80 memset(pre, 0, sizeof(pre)); 81 memset(bccno, 0, sizeof(bccno)); 82 83 dfs_clock = bcc_cnt = 0; 84 for(int i = 0; i < n; i++) 85 if(!pre[i]) dfs(i, -1); 86 } 87 int kase; 88 void solve(int n) 89 { 90 find_bcc(n); 91 LL ans1 = 0, ans2 = 1; 92 for(int i = 1; i <= bcc_cnt; i++) 93 { 94 int cut_cnt = 0; 95 for(int j = 0; j < bcc[i].size(); j++) 96 if(iscut[bcc[i][j]]) cut_cnt++; 97 if(cut_cnt == 1) 98 ans1++, ans2 *= (LL)(bcc[i].size() - cut_cnt); 99 } 100 if(bcc_cnt == 1) 101 { 102 ans1 = 2, ans2 = (LL)(n-1)*n/2; 103 } 104 printf("Case %d: %I64d %I64d\n", kase, ans1, ans2); 105 } 106 int main(void) 107 { 108 int m; 109 while(scanf("%d", &m), m) 110 { 111 kase++; 112 for(int i = 0; i < maxn; i++) 113 g[i].clear(); 114 int mxn = 0; 115 while(m--) 116 { 117 int u, v; 118 scanf("%d%d", &u, &v); 119 mxn = max(mxn, max(u, v)); 120 u--, v--; 121 g[u].pb(v), g[v].pb(u); 122 } 123 solve(mxn); 124 } 125 return 0; 126 }
此题的另一种解法是先求出割顶,然后从非割顶的点dfs一遍,注意这个过程中不能经过割顶,统计每次dfs中遇到割顶的数目,如果为1,则更新答案。同样注意割顶为0的情况。
代码:
1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <climits> 5 #include <cstring> 6 #include <cstdlib> 7 #include <string> 8 #include <stack> 9 #include <map> 10 #include <cmath> 11 #include <vector> 12 #include <queue> 13 #include <algorithm> 14 #define esp 1e-6 15 #define pi acos(-1.0) 16 #define pb push_back 17 #define mp(a, b) make_pair((a), (b)) 18 #define in freopen("in.txt", "r", stdin); 19 #define out freopen("out.txt", "w", stdout); 20 #define print(a) printf("%d\n",(a)); 21 #define bug puts("********))))))"); 22 #define stop system("pause"); 23 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 24 #define inf 0x0f0f0f0f 25 #pragma comment(linker, "/STACK:102400000,102400000") 26 27 using namespace std; 28 typedef long long LL; 29 typedef vector<int> VI; 30 typedef pair<int, int> pii; 31 typedef vector<pii,int> VII; 32 typedef vector<int>:: iterator IT; 33 const int maxn = 50000 + 10; 34 int pre[maxn], low[maxn], iscut[maxn], dfs_clock; 35 VI g[maxn], cut; 36 int n; 37 LL ans1, ans2, cut_cnt; 38 int dfs(int u, int fa) 39 { 40 int lowu = pre[u] = ++dfs_clock; 41 int child = 0; 42 for(int i = 0; i < g[u].size(); i++) 43 { 44 int v = g[u][i]; 45 if(!pre[v]) 46 { 47 child++; 48 int lowv = dfs(v, u); 49 lowu = min(lowu, lowv); 50 if(lowv >= pre[u]) 51 { 52 iscut[u] = 1; 53 } 54 } 55 else if(pre[v] < pre[u] && v != fa) 56 { 57 lowu = min(lowu, pre[v]); 58 } 59 } 60 if(child == 1 && fa < 0) 61 iscut[u] = 0; 62 return low[u] = lowu; 63 } 64 void find_bcc(int n) 65 { 66 memset(pre, 0, sizeof(pre)); 67 memset(iscut, 0, sizeof(iscut)); 68 dfs_clock = 0; 69 for(int i = 0; i < n; i++) 70 if(!pre[i]) 71 dfs(i, -1); 72 } 73 int cnt; 74 void dfs1(int u) 75 { 76 cnt++; 77 pre[u] = 1; 78 for(int i = 0; i < g[u].size(); i++) 79 { 80 int v = g[u][i]; 81 if(!pre[v]) 82 { 83 if(iscut[v]) cut_cnt++, cnt++, pre[v] = 1, cut.pb(v); 84 else dfs1(v); 85 } 86 } 87 } 88 void solve(int n) 89 { 90 cut.clear(); 91 cut_cnt= 0; 92 memset(pre, 0, sizeof(pre)); 93 for(int i = 0; i < n; i++) 94 if(iscut[i]) cut_cnt++; 95 96 if(cut_cnt == 0) ans1 = 2, ans2 = (LL)n*(n-1)/2; 97 else for(int i = 0; i < n; i++) 98 if(!pre[i] && !iscut[i]) 99 { 100 cut_cnt = cnt = 0; 101 dfs1(i); 102 for(int i = 0; i < cut.size(); i++) 103 pre[cut[i]] = 0; 104 cut.clear(); 105 if(cut_cnt == 1) 106 ans1++, ans2 *= (LL)(cnt-1); 107 } 108 } 109 int main(void) 110 { 111 int m, t = 1; 112 while(scanf("%d", &m), m) 113 { 114 n = 0; 115 ans1 = 0, ans2 = 1; 116 for(int i = 0; i < maxn; i++) 117 g[i].clear(); 118 while(m--) 119 { 120 int u, v; 121 scanf("%d%d", &u, &v); 122 n = max(n, max(u, v)); 123 u--, v--; 124 g[u].pb(v); 125 g[v].pb(u); 126 } 127 find_bcc(n); 128 solve(n); 129 printf("Case %d: %I64d %I64d\n", t, ans1, ans2); 130 t++; 131 } 132 return 0; 133 }