UVa 1108 - Mining Your Own Business (tarjan)
题目链接: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\n", ++kase, ans, way);
}
return 0;
}