Popular Cows
| Time Limit: 2000MS |
|
Memory Limit: 65536K |
| Total Submissions: 11739 |
|
Accepted: 4641 |
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 31 22 12 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity. 這道題剛開始我用的普通DFS直接搜尋,不幸的是超記憶體了,因為我無知的開了一個長度為1億的字元數組(PS:以後開大數組前一定要先算一下需要的記憶體),被MLE後不甘心繼續修改,把記憶體降下來後繼續提交,TLE,再改,再TLE。。若干次後我意識到普通演算法好像過不去。。也沒有心思再改了。。。 看了討論才知道這個需要用求強連通分量的tarjan演算法,百度上找到tarjan,看了挺長時間才把他真正看懂。。 看懂了tarjan,我又想了一個多小時,寫出代碼,終於將這道題AC。。真不容易,不過這道題讓我學到了新的東西,A掉這題的成就感很強,在此我要感謝這道題~,還要感謝協助我的小傑同學~!思路:用tarjan演算法求出圖的強連通分量數C,將每個強聯通分量看成一個點(縮點),然後求出每個縮點的出度,判斷這些點的出度是否等於C-1,如果相等,則出度為0的那個連通分支所包含的點數即是所求,否則輸出0。證明:假設已經求出關係圖G的各個連通分量,由連通分支內任意兩點都可達的性質可以得到:該分支內的任意一點都能到達這個點。將每個連通分量縮成一個點,對於一個點來說,只要其他點存在到這個點的單向路徑則這個縮點內包含的點都被其他的連通分支所包含的點支援,因此,題目也就是求關係圖每個連通分支的出度,如果只存在一個出度為0的連通分支則這個聯通分支內包含的點數即是所求,否則不存在被所有牛支援的牛。 #include<iostream><br />using namespace std;<br />int dfn[10010],low[10010],time,C,s[10010],S[10010],top;bool in[10010];<br />struct LIST<br />{<br />int v;LIST *next;<br />};</p><p>LIST *head[10010],*rear[10010];</p><p>int chudu[10010];</p><p>void tarjan(int v)/*tarjan求圖的強連通分量*/<br />{<br />dfn[v]=low[v]=++time;<br />S[top++]=v;<br />in[v]=true;<br />for(LIST *p=head[v];p!=NULL;p=p->next)<br />if(!dfn[p->v])<br />{<br />tarjan(p->v);<br />if(low[p->v]<low[v])<br />low[v]=low[p->v];<br />}<br />else if(in[p->v]&&low[p->v]<low[v])<br />low[v]=low[p->v];</p><p>if(low[v]==dfn[v])<br />{<br />C++;<br />do<br />{<br />v=S[--top];<br />in[v]=false;<br />s[v]=C;/*縮圖,標記屬於同一強連通分量的點*/<br />}while(low[v]!=dfn[v]);<br />}<br />}</p><p>int main()<br />{<br />int n,m,i,a,b;<br />while(cin>>n>>m)<br />{<br />memset(head,0,sizeof(int)*10010);<br />memset(rear,0,sizeof(int)*10010);<br />memset(s,0,sizeof(int)*10010);<br />top=0;<br />for(i=0;i<m;i++)/*鄰接表格儲存體關係圖*/<br />{<br />scanf("%d%d",&a,&b);<br />if(rear[a]!=NULL)<br />{<br />rear[a]->next=new LIST;<br />rear[a]=rear[a]->next;<br />}<br />else<br />head[a]=rear[a]=new LIST;<br />rear[a]->next=NULL;<br />rear[a]->v=b;<br />}<br />time=0;C=0;<br />memset(dfn,0,sizeof(int)*10010);<br />memset(low,0,sizeof(int)*10010);<br />memset(in,0,sizeof(bool));<br />for(i=1;i<=n;i++)<br />if(!dfn[i])<br />tarjan(i);<br />if(C==1)/*如果只有一個強連通分量,則輸出n*/<br />{<br />cout<<n<<endl;<br />continue;<br />}</p><p>memset(chudu,0,sizeof(chudu));</p><p>for(i=1;i<=n;i++)/*計算縮圖後每個點的出度*/<br />for(LIST *p=head[i];p!=NULL;p=p->next)<br />if(s[i]!=s[p->v])<br />chudu[s[i]]=1;<br />a=b=0;<br />for(i=1;i<=C;i++)<br />if(chudu[i])<br />a++;<br />else<br />b=i;<br />if(a==C-1)/*統計出度總數是否為C-1*/<br />{<br />a=0;/*如果出度總數為C-1,則統計出度為0的連通分量包含點的個數*/<br />for(i=1;i<=n;i++)<br />if(s[i]==b)<br />a++;<br />cout<<a<<endl;<br />}<br />else/*如果出度總數不為C-1,則無解,輸出0*/<br />cout<<'0'<<endl;</p><p>}<br />return 0;</p><p>}