题目描述:
有一些奶牛,其中某些奶牛受其他奶牛欢迎。每头奶牛都喜欢自己,同时都追随它喜欢奶牛的爱好。如果A喜欢B,而B喜欢C,那么A也会喜欢C。如果所有人都喜欢某头奶牛,那么这头奶牛就称之为绝对奶牛。
现在有N头奶牛,同时告诉你M条A喜欢B的信息,请你计算出有多少头绝对奶牛。
输入描述:
输入文件第一行是N和M。此后M行,每行两个整数A,B(1<=A,B<=N),表示奶牛B受奶牛A欢迎,也就是奶牛A喜欢奶牛B。
输出描述:
输出文件仅有一行,是绝对奶牛的数目。
输入样例:
3 3
1 2
2 1
2 3
输出样例:
1
数据范围:
对于30%的数据,有1<=N<=1000,1<=M<=5000;
对于100%的数据,有1<=N<=100000,1<=M<=500000。
-----------------------------------------------------------------
Tarjan求强连通分支
代码如下
#include <cstdio> #include <algorithm> struct Edge { int from, to; Edge* next; }; const int MAXN = 100001, MAXM = 500001; struct UFS { int father[MAXN], rank[MAXN], root(int); void initialize(int), plus(int, int); }; int n, m, low[MAXN], dfn[MAXN], nowdfn, stk[MAXN], top, s[MAXN]; Edge* head[MAXN]; bool vis[MAXN], ins[MAXN]; Edge edges[MAXM]; UFS ufs; void dfs(int); int main() { int cnt = 0, tmp; scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) { int s, t; Edge* tmp = new Edge; scanf("%d%d", &s, &t); tmp->from = s; tmp->to = t; tmp->next = head[s]; head[s] = tmp; } ufs.initialize(n); for(int i = 1; i <= n; i++) { if(!vis[i]) { dfs(i); } } for(int i = 1; i <= n; i++) { for(Edge* j = head[i]; j != NULL; j = j->next) { if(ufs.root(i) != ufs.root(j->to)) { s[ufs.root(i)]++; } } } for(int i = 1; i <= n; i++) { if(ufs.root(i) == i && s[i] == 0) { cnt++; tmp = i; } } printf("%d\n", cnt == 1 ? ufs.rank[tmp] : 0); return 0; } void UFS::initialize(int n) { for(int i = 1; i <= n; i++) { father[i] = i; rank[i] = 1; } } int UFS::root(int x) { return father[x] == x ? x : root(father[x]); } void UFS::plus(int x, int y) { father[y] = x; rank[x] += rank[y]; } void dfs(int x) { nowdfn++; top++; dfn[x] = low[x] = nowdfn; ins[x] = vis[x] = true; stk[top] = x; for(Edge* i = head[x]; i != NULL; i = i->next) { int go = i->to; if(!vis[go]) { dfs(go); low[x] = std::min(low[x], low[go]); } if(ins[go]) { low[x] = std::min(low[x], dfn[go]); } } if(dfn[x] == low[x]) { int f = stk[top]; top--; if(f != x) { while(true) { int i = stk[top]; top--; ufs.plus(f, i); if(i == x) { break; } } } } }
但是会爆递归栈只有70分
Egg Pain的我就Egg Pain地写了一个Egg Pain的递归栈模拟,特此纪念,看代码。!
#include <cstdio> #include <algorithm> struct Edge { int from, to; Edge* next; }; const int MAXN = 100001, MAXM = 500001; struct UFS { int father[MAXN], rank[MAXN], root(int); void initialize(int), plus(int, int); ~UFS(); }; struct Cell { int x; bool finished, first, visjto; Edge* j; void call(); }; int n, m, low[MAXN], dfn[MAXN], nowdfn, stk[MAXN], top, s[MAXN], cst; bool vis[MAXN], ins[MAXN]; Edge* head[MAXN]; UFS ufs; Cell cs[MAXN]; int main() { int cnt = 0, tmp; freopen("popular.in", "r", stdin); freopen("popular.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) { int s, t; Edge* tmp = new Edge; scanf("%d%d", &s, &t); tmp->from = s; tmp->to = t; tmp->next = head[s]; head[s] = tmp; } ufs.initialize(n); for(int i = 1; i <= n; i++) { if(!vis[i]) { cst = 1; cs[cst].x = i; cs[cst].first = true; cs[cst].finished = false; while(cst != 0) { cs[cst].call(); if(cs[cst].finished) { cst--; } } } } for(int i = 1; i <= n; i++) { for(Edge* j = head[i]; j != NULL; j = j->next) { if(ufs.root(i) != ufs.root(j->to)) { s[ufs.root(i)]++; } } } for(int i = 1; i <= n; i++) { if(ufs.root(i) == i && s[i] == 0) { cnt++; tmp = i; } } printf("%d\n", cnt == 1 ? ufs.rank[tmp] : 0); for(int i = 1; i <= n; i++) { while(head[i] != NULL) { Edge* tmp = head[i]->next; delete head[i]; head[i] = tmp; } } fclose(stdin); fclose(stdout); return 0; } void UFS::initialize(int n) { for(int i = 1; i <= n; i++) { father[i] = i; rank[i] = 1; } } int UFS::root(int x) { return father[x] == x ? x : root(father[x]); } void UFS::plus(int x, int y) { father[y] = x; rank[x] += rank[y]; } UFS::~UFS() { delete[] father; delete[] rank; } void Cell::call() { if(first) { nowdfn++; top++; dfn[x] = low[x] = nowdfn; ins[x] = vis[x] = true; stk[top] = x; j = head[x]; first = false; } else { if(!visjto) { low[x] = std::min(low[x], low[j->to]); } if(ins[j->to]) { low[x] = std::min(low[x], dfn[j->to]); } j = j->next; } if(j == NULL) { if(low[x] == dfn[x]) { int f = stk[top]; top--; if(f != x) { while(true) { int i = stk[top]; top--; ufs.plus(f, i); if(i == x) { break; } } } } finished = true; } else { if(!vis[j->to]) { cst++; cs[cst].x = j->to; cs[cst].first = true; cs[cst].finished = false; visjto = false; } else { visjto = true; } } }