Popular Cows
| Time Limit: 2000MS |
|
Memory Limit: 65536K |
| Total Submissions: 13835 |
|
Accepted: 5484 |
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.
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.
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
Hint
Cow 3 is the only cow of high popularity.
Source
/* POJ2186 1.求出所有的強連通分量,用Korasaju算法 2.每個強連通分量縮成一點,則形成一個有向無環圖DAG。 3.DAG上面如果有唯一的出度為0的點,則改點能被所有的點可達。 那么該點所代表的連通分量上的所有的原圖中的點,都能被原圖中 的所有點可達 ,則該連通分量的點數就是答案。 4.DAG上面如果有不止一個出度為0的點,則這些點互相不可達,原問題 無解,答案為0; (此外DAG肯定是一個有向無環圖,則至少存在一個出度為0的點,上面 兩種情況包括了所有可能。 此題用了鄰接表存圖,并利用鄰接表進行DFS,需要學習下。) */ #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define MAXN 10005 //結點的最大數 struct Node { int to,next; }edge1[MAXN*5],edge2[MAXN*5]; //edge1用來存原圖G,edge2用來存GT,即逆圖 //都是用鄰接表來儲存的圖, int head1[MAXN];//原圖的鄰接表的頭結點 int head2[MAXN];//逆圖的鄰接表的頭結點 int mark1[MAXN],mark2[MAXN]; int tot1,tot2; int cnt1,cnt2,st[MAXN],belong[MAXN]; int num,setNum[MAXN]; struct Edge { int l,r; }e[MAXN*5];//儲存邊
void add(int a,int b)//添加邊a->b,在原圖和逆圖都需要添加 { edge1[tot1].to=b;edge1[tot1].next=head1[a];head1[a]=tot1++;//鄰接表存的原圖 edge2[tot2].to=a;edge2[tot2].next=head2[b];head2[b]=tot2++;//鄰接表存的逆圖 } void DFS1(int x)//深度搜索原圖 { mark1[x]=1; for(int i=head1[x];i!=-1;i=edge1[i].next) if(!mark1[edge1[i].to]) DFS1(edge1[i].to); st[cnt1++]=x;//st數組是按照完成時間從小到大排序的 } void DFS2(int x)//深度搜索逆圖 { mark2[x]=1; num++; belong[x]=cnt2; for(int i=head2[x];i!=-1;i=edge2[i].next) if(!mark2[edge2[i].to]) DFS2(edge2[i].to); } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { tot1=tot2=1; for(int i=1;i<=n;i++)//初始化 { head1[i]=head2[i]=-1; mark1[i]=mark2[i]=0; } for(int i=1;i<=m;i++) { int w,v; scanf("%d%d",&w,&v); e[i].l=w;e[i].r=v;//儲存邊 add(w,v);//建立鄰接表 } cnt1=cnt2=1; for(int i=1;i<=n;i++) { if(!mark1[i])DFS1(i); } for(int i=cnt1-1;i>=1;i--) { if(!mark2[st[i]]) { num=0; DFS2(st[i]); setNum[cnt2++]=num; } } int de[MAXN];//計算出度 memset(de,0,sizeof(de)); for(int i=1;i<=m;i++)//計算各個DAG圖的出度 { if(belong[e[i].l]!=belong[e[i].r])//原圖的邊不屬于同一連通分支 de[belong[e[i].l]]++; } //計算DAG出度為0的個數 int cnt=0,res; for(int i=1;i<cnt2;i++) if(!de[i]){cnt++;res=i;} if(cnt>1) printf("0\n"); else printf("%d\n",setNum[res]); } return 0; }
/* Kosaju算法比較好理解,就是先對逆圖作一遍dfs,計算后序編號定義頂點的排列(如果有向圖是一個DAG, 這一過程產生一個拓撲排序序列)。然后在圖上再一次DFS,不過是按照具有最高后序編號的未訪問的頂點的順
序。 這樣得到的就是一個強連通分量了。因為在訪問逆圖的時候,只有當原圖中w點可以到達v點的時候, 逆圖中的dfs樹中V才可能是W的父節點,也就是說逆圖中V可到達w,這樣,v的編號將大于w。再在原圖中作DFS
, 由于是按照先訪問最高后序未訪問編號的次序,這樣如果在原圖中w可以到達v,那么在逆圖中就有V可以到達w */ #include<cstdio> #include<cstring> #include<iostream> #define M 10005 //結點數 using namespace std;
struct node{ int to,next; }edge1[M*10],edge2[M*10]; int mark1[M],mark2[M],head1[M],head2[M]; int tot1,tot2; int cnt1,st[M],cnt2,belong[M]; int num,setNum[M]; struct nn{ int l,r; }e[M*10];
void add(int a,int b){ //每個點的前端結點 和 后端結點 edge1[tot1].to=b, edge1[tot1].next=head1[a], head1[a]=tot1++;//鄰接表存的原圖 edge2[tot2].to=a, edge2[tot2].next=head2[b], head2[b]=tot2++;//鄰接表存的逆圖 } void DFS1(int x) { mark1[x]=1; for(int i=head1[x]; i!=-1; i=edge1[i].next) //正向 if(!mark1[edge1[i].to]) DFS1(edge1[i].to); st[cnt1++]=x; } void DFS2(int x) { mark2[x]=1; num++; belong[x]=cnt2; //正向能到,反向也能到的是在同一聯通分量里 for(int i=head2[x]; i!=-1; i=edge2[i].next) //逆向 if(!mark2[edge2[i].to]) DFS2(edge2[i].to); } int main() { int n,m; while(scanf("%d%d",&n,&m) != EOF){ tot1=tot2=0; for(int i=0; i<n; i++){ head1[i]=head2[i]=-1; mark1[i]=mark2[i]=0; } for(int i=0; i<m; i++){ int w,v; scanf("%d%d",&w,&v); w--, v--; //結點從0開始編號 e[i].l=w; e[i].r=v; add(w,v); } cnt1=cnt2=0; for(int i=0; i<n; i++){ if(!mark1[i]) DFS1(i); } for(int i=cnt1-1; i>=0; i--){ if(!mark2[ st[i] ]) { num=0; DFS2(st[i]); setNum[cnt2++]=num; } } int de[M]; memset(de,0,sizeof(de)); for(int i=0; i<m; i++){ if(belong[ e[i].l ] != belong[ e[i].r ]) de[ belong[e[i].l] ]++; } int cnt=0,res; for(int i=0; i<cnt2; i++){ if(!de[i]) { cnt++; res=i; } } if(cnt>1) printf("0\n"); else printf("%d\n",setNum[res]); } return 0; }
|
|
|
| | 日 | 一 | 二 | 三 | 四 | 五 | 六 |
|---|
| 31 | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | 10 | 11 | 12 | 13 | | 14 | 15 | 16 | 17 | 18 | 19 | 20 | | 21 | 22 | 23 | 24 | 25 | 26 | 27 | | 28 | 29 | 30 | 31 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
公告
導航
統計
- 隨筆: 100
- 文章: 0
- 評論: 2
- 引用: 0
常用鏈接
留言簿(2)
隨筆分類
隨筆檔案
博客
搜索
最新評論

閱讀排行榜
評論排行榜
|
|