核心:因为入度不为0的联通块,总能通过它所连接的块连到s所在块上。
vector版本:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 5010;
vector<int> vec[maxn];
int dfn[maxn];
int low[maxn];
int Stack[maxn], top;
bool Instack[maxn];
int index, number;
int belong[maxn], num[maxn]; //num数组不需要
int n, m, s;
int inDegree[maxn];
int ans;void tarjan(int u)
{dfn[u] = low[u] = index++;Stack[top++] = u;Instack[u] = 1;int sz = vec[u].size();for(int i = 0; i < sz; i++){int v = vec[u][i];if(!dfn[v]){tarjan(v);if(low[v] < low[u])low[u] = low[v];}else{if(Instack[v] && dfn[v] < low[u]){low[u] = dfn[v];}}}int j;if(low[u] == dfn[u]){number++;do{j = Stack[--top];Instack[j] = 0;belong[j] = number;num[number]++;}while(j != u);}
}void solve(int s)
{ans = 0;for(int i = 1; i <= n; i++)if(!dfn[i])tarjan(i);if(number == 1){puts("0"); return;}inDegree[belong[s]] = 1; //注意是belong[s], s所在连通块,不是s//for(int i = 1; i <= n; i++)//cout << belong[i] << " ";//cout << endl;for(int i = 1; i <= n; i++){int sz = vec[i].size();for(int j = 0; j < sz; j++){int v = vec[i][j];if(belong[i] == belong[v]) continue;inDegree[belong[v]]++; //belong[v]}}for(int i = 1; i <= number; i++) //上限是number,容易写错为nif(!inDegree[i]){ans++;}cout << ans << endl;
}int main()
{cin >> n >> m >> s;int a, b;for(int i = 0; i < m; i++){cin >> a >> b;vec[a].push_back(b);}index = 1, top = 1, number = 0;solve(s);return 0;
}
链式前向星版本:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5010;
int dfn[maxn], low[maxn], tot;
struct Edge
{int to;int next;
}edge[maxn];int head[maxn], cnt;
int stack[maxn];
bool vis[maxn];
int belong[maxn];
int top, number;
int n, m, s;
int indegree[maxn];void init()
{memset(head, -1, sizeof(head));memset(dfn, 0, sizeof(dfn));memset(low, 0, sizeof(low));cnt = 0;tot = 1; //indextop = 0;number = 0;
}void addEdge(int a, int b)
{edge[cnt].to = b;edge[cnt].next = head[a];head[a] = cnt++;
}void tarjan(int u)
{dfn[u] = low[u] = tot++;stack[++top] = u;vis[u] = 1;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[j].to; //注意不要误写成iif(!dfn[v]){tarjan(v);if(low[v] < low[u])low[u] = low[v];}else{if(vis[v] && dfn[v] < low[u])low[u] = dfn[v];}}int j;if(dfn[u] == low[u]){number++;do{j = stack[top--];vis[j] = 0;belong[j] = number;}while(j != u);}
}int main()
{cin >> n >> m >> s;init();int a, b;for(int i = 0; i < m; i++){scanf("%d%d", &a, &b);addEdge(a, b);}for(int i = 1; i <= n; i++){if(!dfn[i])tarjan(i);}int ans = 0;if(number == 1)ans = 0;else{indegree[belong[s]] = 1; //保证起点所在连通块排除for(int i = 1; i <= n; i++){for(int j = head[i]; j != -1; j = edge[j].next){int to = edge[j].to;//cout << i << " " << to << endl;if(belong[i] == belong[to]) continue;indegree[belong[to]]++;}}for(int i = 1; i <= number; i++)if(!indegree[i])ans++;}cout << endl;printf("%d\n", ans);return 0;
}