学习了一下tarjan, 主要是学一下缩点(抄板子)。
题目链接:受欢迎的牛
#include <bits/stdc++.h>
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<int> 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 <bits/stdc++.h>
#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<int> 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<<ssc_cnt<<endl;
for(int i = 1; i<=n; i++) head[i] = 0;
for(int i = 1; i<=m; i++) edge[i].next = edge[i].to = 0;
cnt = 0;
for(int i = 1; i<=m; i++){
if(col[u[i]] != col[v[i]]) add_edge(col[u[i]], col[v[i]]);
}
ll ans = 0;
for(int i = 1; i<=ssc_cnt; i++){
if(!dp[i]){
dfs(i);
ans = max(ans, dp[i]);
}
}
printf("%lld", ans);
return 0;
}