POJ_2186_Popular Cows_强连通分量
Popular Cows
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 30680 | Accepted: 12445 |
Description
Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3 1 2 2 1 2 3
Sample Output
1
大意:n只牛,m对数(a,b)表示a认为b牛逼。若a认为b牛逼,b认为c牛逼,那么a也认为c牛逼。问n只牛中,有多少只牛是其他所有牛都认为牛逼的。
分析:若图为不连通,则答案为0.当图连通时,在同一个强连通分量A中的牛在被该强连通分量中其他牛认为牛逼;若在A和另一个强连通分量B之间有路,假设A指向B,则A中的牛都认为B中的牛是牛逼的。任意一个有向图都可以分解成若干不相交的强连通分量,把每个强连通分量缩点,就得到一个DAG(有向无环图)。该题要找的是缩点后DAG中出度为0的点所表示的强连通分量中的点数。(该出度为0的点一定唯一,否则不可能有其他牛都认为牛逼的牛)
求强连通分量可使用tarjan算法。
当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
void tarjan(int s) { vis[s]=2; dfn[s]=low[s]=++now; sta.push(s); for(int i=0; i<gra[s].size(); i++) { int t=gra[s][i]; if(dfn[t]==0) { tarjan(t); low[s]=min(low[s],low[t]); } else if(vis[t]==2) low[s]=min(low[s],dfn[t]); } if(low[s]==dfn[s]) { sum++; while(!sta.empty()) { int t=sta.top(); sta.pop(); vis[t]=1; num[t]=sum; if(t==s) break; } } }
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stdlib.h> #include<vector> #include<stack> using namespace std; #define LL long long #define N 10005 vector<int> gra[N]; stack<int>sta; int n,m,dfn[N],low[N],vis[N],num[N]; int degree[N],sum,now,res,loc; void init() { sum=0; now=0; res=0; memset(vis,0,sizeof(vis)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(degree,0,sizeof(degree)); for(int i=0; i<=n; i++) gra[i].clear(); while(!sta.empty()) sta.pop(); } void read() { int a,b; scanf("%d%d",&n,&m); for(int i=0; i<m; i++) { scanf("%d%d",&a,&b); gra[a].push_back(b); } } void tarjan(int s) { vis[s]=2; dfn[s]=low[s]=++now; sta.push(s); for(int i=0; i<gra[s].size(); i++) { int t=gra[s][i]; if(dfn[t]==0) { tarjan(t); low[s]=min(low[s],low[t]); } else if(vis[t]==2) low[s]=min(low[s],dfn[t]); } if(low[s]==dfn[s]) { sum++; while(!sta.empty()) { int t=sta.top(); sta.pop(); vis[t]=1; num[t]=sum; //缩点 if(t==s) break; } } } void solve() { for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i); for(int i=1; i<=n; i++) for(int j=0; j<gra[i].size(); j++) if(num[i]!=num[gra[i][j]]) degree[num[i]]++; //对缩点后的DAG进行出度的统计 for(int i=1; i<=sum; i++) { if(degree[i]==0) { res++; loc=i; //第几个强连通分量 } } if(res>1) printf("0\n"); else { res=0; for(int i=1; i<=n; i++) if(num[i]==loc) res++; printf("%d\n",res); } } int main() { init(); read(); solve(); return 0; } /* 3 3 1 2 2 1 2 3 */