Tarjan

例题：CF427 C.CheckPosts

Input 1：

3
1 2 3
3
1 2
2 3
3 2


Output 1

3 1


Input 2:

5
2 8 0 6 0
6
1 4
1 3
2 4
3 4
4 5
5 1


Output 2:

8 2

Input 3:

10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9


Output 3:

15 6

Input 4:

2
7 91
2
1 2
2 1


Output 4:

7 1

AC代码：

#include<set>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
typedef long long LL;
#define PII pair<int, int>
#define pb push_back
const int maxn = 1e5 + 5;
const LL mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
using namespace std;

int n, m;
LL MinAllCost, Method = 1;
vector<int> Tcnt[maxn];
LL TMinCost[maxn];//联通分量内最小花费point
int S[maxn];//栈
int dfn[maxn], low[maxn];//
int sig, Top = -1, cnt;//连通分量标号，栈顶，dfn
int vis[maxn];
LL cost[maxn];
vector<int> G[maxn];

void Tarjan(int x){
vis[x] = 1;
low[x] = dfn[x] = ++cnt;
S[++Top] = x;
int len = G[x].size();
for(int i = 0; i < len; ++i){
int v = G[x][i];
if(vis[v] == 0) Tarjan(v);
if(vis[v] == 1) low[x] = min(low[x], low[v]);
}
if(dfn[x] == low[x]){
sig++;
//printf("when sig++ : x = %d\n", x);
while(1){
low[S[Top]] = sig;
vis[S[Top]] = -1;
Tcnt[sig].pb(S[Top]);//连通分量内所有点
//printf("%d ", S[Top]);
TMinCost[sig] = min(TMinCost[sig], cost[S[Top]]);
if(S[Top--] == x) break;
}
//printf("\n");
}
}

int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf(" %lld", cost + i);
}
scanf("%d", &m);
for(int i = 1; i <= m;++i){
int u, v;
scanf("%d %d", &u, &v);
G[u].pb(v);
}
memset(TMinCost, inf, sizeof TMinCost);
for(int i = 1; i <= n; ++i) if(vis[i] == 0) Tarjan(i);
//printf("Sig = %d\n", sig);
for(int i = 1; i <= sig; ++i){
MinAllCost += TMinCost[i];
int len = Tcnt[i].size();
//printf("sig = %d : len = %d\n", i, len);
LL cnt = 0;
for(int j = 0; j < len; ++j){
if(cost[Tcnt[i][j]] == TMinCost[i]) cnt++;
}
Method = Method * cnt % mod;
}
printf("%lld %lld\n", MinAllCost, Method);
return 0;
}

Tarjan算法模板：(POJ2553)

int sig;//连通分量标号
int Top;//栈顶坐标
int Stack[maxn];//栈
int cnt;//dfn
int dfn[maxn], low[maxn];
vector<int> G[maxn];//存图
int vis[maxn];//标记
int color[maxn];//染色缩点

int degree[maxn];//出度 for poj 2553

void Tarjan(int x){
vis[x] = 1;
Stack[++Top] = x;
low[x] = dfn[x] = ++cnt;
int len = G[x].size();
for(int i = 0; i < len; ++i){
int v = G[x][i];
if(vis[v] == 0) Tarjan(v);
if(vis[v] == 1) low[x] = min(low[x], low[v]);
}
if(dfn[x] == low[x]){
sig++;
while(1){
low[Stack[Top]] = sig;
vis[Stack[Top]] = -1;
color[Stack[Top]] = sig;
if(Stack[Top--] == x) break;
}
}
}

int main(){
int n, m;//n点m边
while(~ scanf("%d", &n) && n){
scanf("%d", &m);
Top = 0;
sig = 0;
cnt = 0;
for(int i = 1; i <= n; ++i) {
G[i].clear();
vis[i] = 0;
color[i] = 0;
dfn[i] = 0;
low[i] = 0;
degree[i] = 0;
Stack[i] = 0;
}
for(int i = 1; i <= m; ++i){
int u, v;
scanf("%d %d", &u, &v);
G[u].pb(v);
}
for(int i = 1; i <= n; ++i){
if(vis[i] == 0) Tarjan(i);
}
//-------------------------------
for(int i = 1; i <= n; ++i){
int len = G[i].size();
for(int j = 0; j < len; ++j){
int v = G[i][j];
if(color[i] != color[v]) degree[color[i]]++;
}
}
vector<int> ans;
for(int i = 1; i <= sig; ++i){
if(degree[i]) continue;
for(int j = 1; j <= n; ++j){
if(color[j] == i) ans.pb(j);
}
}
sort(ans.begin(), ans.end());
for(int i = 0; i < ans.size() - 1; ++i) printf("%d ", ans[i]);
printf("%d\n", ans[ans.size() - 1]);
//--------------poj2553---------
}
return 0;
}


©️2019 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客