UVa 1108

题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=0&problem=3549&mosmsg=Submission+received+with+ID+26579033

求出图中的所有双连通分量,如果整张图都是双连通分量,则任选两个点涂黑。

否则枚举双连通分量,如果该分量中有一个割点,那么该分量要选一个点涂黑(不涂割点),否则无需涂该分量(因为总有另一个割点通往其他的分量)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 50010;

int n, m;

int h[maxn], cnt = 0;
struct E{
	int from, to, next;
//	E(int from, int to, int next): from(from), to(to), next(next){}
}e[maxn << 1];
void add(int u, int v){
	e[++cnt].to = v;
	e[cnt].from = u;
	e[cnt].next = h[u]; 
	h[u] = cnt;
}

stack<E> s;
vector<int> bcc[maxn];
int st[maxn], low[maxn], iscut[maxn], bccno[maxn], dfn = 0, bcc_cnt = 0;

int dfs(int u, int par){
	low[u] = st[u] = ++dfn;
	
	int child = 0;
	for(int i = h[u] ; i != -1 ; i = e[i].next){
		int v = e[i].to;
		E ee = (E){u, v, -1};
		if(!st[v]){
			s.push(ee);
			++child;
			low[v] = dfs(v, u);
			low[u] = min(low[u], low[v]);
			
			if(low[v] >= st[u]){
				iscut[u] = 1;
				++bcc_cnt;
				bcc[bcc_cnt].clear();
				for(;;){
					E x = s.top(); s.pop();
					if(bccno[x.from] != bcc_cnt) { bcc[bcc_cnt].push_back(x.from); bccno[x.from] = bcc_cnt; }
					if(bccno[x.to] != bcc_cnt) { bcc[bcc_cnt].push_back(x.to); bccno[x.to] = bcc_cnt; }
					if(x.from == u && x.to == v) break;
				}
			}
		} else if(st[v] < st[u] && v != par){
			s.push(ee);
			low[u] = min(low[u], st[v]);
		}
	}
	
	if(par == 0 && child == 1) iscut[u] = 0;
	return low[u];
}

void tarjan(){
	memset(st, 0, sizeof(st));
	memset(iscut, 0, sizeof(iscut));
	memset(low, 0, sizeof(low));	
	memset(bccno, 0, sizeof(bccno));
	dfn = 0; bcc_cnt = 0;
	
	for(int i = 1 ; i <= n ; ++i){
		if(!st[i]){
			dfs(1, 0);
		}
	}
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	int kase = 0;
	while(scanf("%d", &m) && m){
		n = 0; 

		memset(h, -1, sizeof(h)); cnt = 0;
		
		int u, v;
		for(int i = 1 ; i <= m ; ++i){
			scanf("%d%d", &u, &v);
			add(u, v); add(v, u);
			n = max(n, u); n = max(n, v);
		}
		
		tarjan();
		
		int ans = 0; ll way = 0;
		if(bcc_cnt == 1){
			ans = 2;
			way = 1ll * n * (n - 1) / 2;
		} else{
			way = 1ll;
			for(int i = 1 ; i <= bcc_cnt ; ++i){
				int tot = 0;
				for(int j = 0 ; j < bcc[i].size() ; ++j){
					if(iscut[bcc[i][j]]){
						++tot;
					}
				}
				if(tot == 1) {
					++ans;
					way = 1ll * way * (bcc[i].size() - 1);
				}
			}
		}
		printf("Case %d: %d %lld
", ++kase, ans, way);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/15022399.html