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.求出所有的強(qiáng)連通分量,用Korasaju算法 2.每個(gè)強(qiáng)連通分量縮成一點(diǎn),則形成一個(gè)有向無環(huán)圖DAG。 3.DAG上面如果有唯一的出度為0的點(diǎn),則改點(diǎn)能被所有的點(diǎn)可達(dá)。 那么該點(diǎn)所代表的連通分量上的所有的原圖中的點(diǎn),都能被原圖中 的所有點(diǎn)可達(dá) ,則該連通分量的點(diǎn)數(shù)就是答案。 4.DAG上面如果有不止一個(gè)出度為0的點(diǎn),則這些點(diǎn)互相不可達(dá),原問題 無解,答案為0; (此外DAG肯定是一個(gè)有向無環(huán)圖,則至少存在一個(gè)出度為0的點(diǎn),上面 兩種情況包括了所有可能。 此題用了鄰接表存圖,并利用鄰接表進(jìn)行DFS,需要學(xué)習(xí)下。) */ #include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define MAXN 10005 //結(jié)點(diǎn)的最大數(shù) struct Node { int to,next; }edge1[MAXN*5],edge2[MAXN*5]; //edge1用來存原圖G,edge2用來存GT,即逆圖 //都是用鄰接表來儲存的圖, int head1[MAXN];//原圖的鄰接表的頭結(jié)點(diǎn) int head2[MAXN];//逆圖的鄰接表的頭結(jié)點(diǎn) 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數(shù)組是按照完成時(shí)間從小到大排序的 } 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];//計(jì)算出度 memset(de,0,sizeof(de)); for(int i=1;i<=m;i++)//計(jì)算各個(gè)DAG圖的出度 { if(belong[e[i].l]!=belong[e[i].r])//原圖的邊不屬于同一連通分支 de[belong[e[i].l]]++; } //計(jì)算DAG出度為0的個(gè)數(shù) 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,計(jì)算后序編號定義頂點(diǎn)的排列(如果有向圖是一個(gè)DAG, 這一過程產(chǎn)生一個(gè)拓?fù)渑判蛐蛄校?。然后在圖上再一次DFS,不過是按照具有最高后序編號的未訪問的頂點(diǎn)的順
序。 這樣得到的就是一個(gè)強(qiáng)連通分量了。因?yàn)樵谠L問逆圖的時(shí)候,只有當(dāng)原圖中w點(diǎn)可以到達(dá)v點(diǎn)的時(shí)候, 逆圖中的dfs樹中V才可能是W的父節(jié)點(diǎn),也就是說逆圖中V可到達(dá)w,這樣,v的編號將大于w。再在原圖中作DFS
, 由于是按照先訪問最高后序未訪問編號的次序,這樣如果在原圖中w可以到達(dá)v,那么在逆圖中就有V可以到達(dá)w */ #include<cstdio> #include<cstring> #include<iostream> #define M 10005 //結(jié)點(diǎn)數(shù) 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){ //每個(gè)點(diǎn)的前端結(jié)點(diǎn) 和 后端結(jié)點(diǎn) 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; //正向能到,反向也能到的是在同一聯(lián)通分量里 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--; //結(jié)點(diǎn)從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 |
|
公告
導(dǎo)航
統(tǒng)計(jì)
- 隨筆: 100
- 文章: 0
- 評論: 2
- 引用: 0
常用鏈接
留言簿(2)
隨筆分類
隨筆檔案
博客
搜索
最新評論

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