Tarjan 缩点的板子

学习了一下tarjan, 主要是学一下缩点(抄板子)。

题目链接:受欢迎的牛

#include 
using namespace std;
const int MAXN = 1e5+5, MAXM = 5e5;
int dfn[MAXN], low[MAXN], tot = 0;
int col[MAXN], ssc_cnt;  //染色 
bool instack[MAXN];
stack stk;
int Size[MAXN]; //记录每个ssc的大小 

int head[MAXN], cnt;
struct EDGE{
	int to, next;
}edge[MAXM];
void add_edge(int u, int v){
	++cnt;
	edge[cnt].to = v, edge[cnt].next = head[u], head[u] = cnt;
}
void Tarjan(int u){
	dfn[u] = low[u] = ++tot;
	stk.push(u);
	instack[u] = true;
	for(int i = head[u]; i; i = edge[i].next){
		int v = edge[i].to;
		if(!dfn[v]){
			Tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(instack[v]){ //说明是后向边 
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]){ //是scc中第一个被访问的节点 
		col[u] = ++ssc_cnt;
		while(stk.top()!=u) {
			col[stk.top()] = ssc_cnt;
			instack[stk.top()] = false;
			Size[ssc_cnt]++;
			stk.pop();
		} 
		instack[u] = false; //还有u
		Size[ssc_cnt]++;
		stk.pop();
	}
}
int dout[MAXN]; //记录出度 
int main(){
	int n, m, u, v; scanf("%d%d", &n, &m);
	while(m--){
		scanf("%d%d", &u, &v);
		add_edge(u, v);
	}
	for(int i=1; i<=n; i++){
		if(!dfn[i]) Tarjan(i);
	}
	for(int i=1; i<=n; i++){
		for(int j = head[i]; j; j = edge[j].next){
			int v = edge[j].to;
			int a = col[i], b = col[v];
			if(a != b){
				dout[a]++;
			}
		}
	}
	int z = 0, sum = 0;
	for(int i = 1; i<=ssc_cnt; i++){
		if(!dout[i]){
			z++;
			sum += Size[i];
			if(z>1){
				sum = 0;
				break;
			}
		}
	}
	printf("%d\n", sum);
	return 0;
}

题目链接:洛谷 模板缩点

#include 
#define ll long long
using namespace std;
const int N = 1e4+5, M = 1e5+10;
struct EDGE{
	int to, next;
}edge[M];
int head[N], cnt; 
void add_edge(int u, int v){
	edge[++cnt].to = v, edge[cnt].next = head[u], head[u] = cnt;
}
int val[N], dfn[N], low[N], ssc_cnt, instack[N], col[N], tot;
stack stk;
ll sum[N];
void tarjan(int u){
	dfn[u] = low[u] = ++tot;
	stk.push(u);
	instack[u] = true;
	for(int i=head[u]; i; i = edge[i].next){
		int v = edge[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} 
		else if(instack[v]){ //后向边 
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]){
		col[u] = ++ssc_cnt;
		while(stk.top() != u){
			col[stk.top()] = ssc_cnt;
			instack[stk.top()] = false;
			sum[ssc_cnt] += val[stk.top()];
			stk.pop();
		}
		stk.pop();
		instack[u] = false;
		sum[ssc_cnt] += val[u];
	}
} 
int u[M], v[M];
ll dp[N];
void dfs(int x){
	if(dp[x]) return;
	dp[x] = sum[x];
	ll nowsum = 0;
	for(int i = head[x]; i; i = edge[i].next){
		int v = edge[i].to;
		dfs(v);
		nowsum = max(nowsum, dp[v]);
	}
	dp[x] +=nowsum;
}
int main() {
	int n, m; scanf("%d%d", &n, &m);
//	for(int i = 1; i<=n; i++) scanf("%d", &val[i]);
	for(int i = 1; i<=m; i++){
		scanf("%d%d", &u[i], &v[i]);
		add_edge(u[i], v[i]);
	}
	for(int i = 1; i<=n; i++){
		if(!dfn[i]) tarjan(i);
	}
	cout<

 

你可能感兴趣的:(图论)