poj2186 强连通分量 targan算法的应用
这个题的意思是给你一些牛和一些边, 假设A 膜拜 B, B膜拜C, 那么A就膜拜C, 然后让你求被其他所有的牛都膜拜的牛的个数, 使用targan算法缩点, 将图变成有向无环图DAG 之后统计顶点的入度, 假设顶点入度为0的个数超过了1, 那么答案是0, 否则输出这个集合的牛的数量。 代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 10000+100; int outdegree[maxn]; struct Tarjan { int setnum[maxn]; int V; struct edge { int u, v; int opp(int k) { return k==u?v:u; } }; vector<edge> e; //边 vector<int> G[maxn]; //u连接的边 int DFN[maxn], low[maxn], sk[maxn]; int belong[maxn]; bool instack[maxn]; int top, Bcnt, Dindex; void init() { memset(setnum, 0, sizeof(setnum)); e.clear(); for(int i=0; i<=V; i++) G[i].clear(); } void add_edge(int u, int v) { e.push_back((edge){u, v}); G[u].push_back(e.size()-1); } void dfs(int u) { DFN[u]=low[u]=++Dindex; instack[u] = true; sk[++top] = u; //入栈 for(int i=0; i<G[u].size(); i++) { int v = G[u][i]; v = e[v].opp(u); //u连接的边v if(!DFN[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(instack[v]) low[u] = min(low[u], DFN[v]); } if(DFN[u] == low[u]) { Bcnt++; int v; do { v = sk[top--]; instack[v] = false; belong[v]=Bcnt; setnum[Bcnt]++; }while(v!=u); } } void targan() { top = Bcnt = Dindex = 0; memset(DFN, 0, sizeof(DFN)); for(int i=1; i<=V; i++) if(!DFN[i]) dfs(i); } }ta; int main() { int n, m; //n个顶点 m条边 scanf("%d%d", &n, &m); ta.V = n; ta.init(); for(int i=0; i<m; i++) { int u, v; scanf("%d%d", &u, &v); ta.add_edge(u, v); } ta.targan(); memset(outdegree, 0, sizeof(outdegree)); for(int i=0; i<ta.e.size(); i++) { int u=ta.e[i].u, v=ta.e[i].v; if(ta.belong[u] != ta.belong[v]) outdegree[ta.belong[u]]++; } int num=0, tp=0; for(int i=1; i<=ta.Bcnt; i++) { if(outdegree[i]==0) num++, tp=i; } if(num>1) printf("0\n"); else printf("%d\n", ta.setnum[tp]); return 0; }