1. 程式人生 > >【codevs2822】愛在心中

【codevs2822】愛在心中

amp class 連通塊 push 卻又 names rdquo nod script

題目描述 Description

“每個人都擁有一個夢,即使彼此不相同,能夠與你分享,無論失敗成功都會感動。愛因為在心中,平凡而不平庸,世界就像迷宮,卻又讓我們此刻相逢Our Home。”

在愛的國度裏有N個人,在他們的心中都有著一個愛的名單,上面記載著他所愛的人(不會出現自愛的情況)。愛是具有傳遞性的,即如果A愛B,B愛C,則A也愛C。
如果有這樣一部分人,他們彼此都相愛,則他們就超越了一切的限制,用集體的愛化身成為一個愛心天使。
現在,我們想知道在這個愛的國度裏會出現多少愛心天使。而且,如果某個愛心天使被其他所有人或愛心天使所愛則請輸出這個愛心天使是由哪些人構成的,否則輸出-1。

輸入描述 Input Description

第1行,兩個數N、M,代表愛的國度裏有N個人,愛的關系有M條。
第2到第M+1行,每行兩個數A、B,代表A愛B。

輸出描述 Output Description

第1行,一個數,代表愛的國度裏有多少愛心天使。
第2行,如果某個愛心天使被其他所有人和愛心天使所愛則請輸出這個愛心天使是由哪些人構成的(從小到大排序),否則輸出-1。

樣例輸入 Sample Input

樣例輸入1:

6 7
1 2
2 3
3 2
4 2
4 5
5 6
6 4

樣例輸入2:

3 3
1 2
2 1
2 3

樣例輸出 Sample Output

樣例輸出1:

2
2 3

樣例輸出2:

1
-1

題目意思:

給個圖,每個環都算作一個愛心天使(一個點不算環)。第一問求多少個愛心天使,第二問求一個特殊愛心天使(其他任何人都可以將愛傳遞到這個愛心天使),假如沒有就輸出-1,反之將這個愛心天使內的人按從小到大輸出。

想法(以下的圖是引用dalao的,表示感謝)

既然求環,不如用強連通分量?

先求出強連通分量,將同一個環內所有元素縮成一個點(包括一個點的),計算出多少個環(這裏不包括一個點的)。

縮點示範圖(與題目不違和的圖):

技術分享

第一問就Ok了。

我們可以發現特殊的愛心天使是一個出度為0的縮點。

但並不是出度為0的縮點就是特殊天使下面又有三種情況:

情況①:

出度為0的並不是天使(如3)

技術分享

情況②:

不只一個出度為0的天使或人(如圖中4、1、3)

技術分享

情況③:只有一個出度為0且為天使(如圖中4)

技術分享


我們需要的是情況③。

那麽就在縮完點後,判斷是否有多個出度為0,是否特殊天使只有一個元素。

於是乎可以寫了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 #define maxn 10005
 7 using namespace std;
 8 int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
11     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
12     return x*f;
13 }
14 struct node{int to,next;}e[maxn*2];
15 int n,m,cnt,last[maxn],dfn[maxn],low[maxn],idex=0,Bcnt=0,belong[maxn],instack[maxn],v[maxn],cd[maxn];
16 stack<int> stap;
17 void add(int u,int v){
18     e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
19 }
20 void tarjan(int s){
21     int t;
22     dfn[s]=low[s]=++idex;
23     stap.push(s);instack[s]=1;
24     for(int i=last[s];i;i=e[i].next){
25         t=e[i].to;
26         if(!dfn[t]){
27             tarjan(t);
28             low[s]=min(low[s],low[t]);
29         }
30         else if(instack[t]) low[s]=min(low[s],low[t]);
31     }
32     if(dfn[s]==low[s]){
33         Bcnt++;
34         do{
35             t=stap.top();stap.pop();
36             instack[t]=0;
37             belong[t]=Bcnt;
38             v[Bcnt]++;
39         }while(s!=t);
40     }
41 }
42 int main(){
43     n=read(),m=read();
44     for(int i=1;i<=m;i++){
45         int u=read(),v=read();
46         add(u,v);
47     }
48     for(int i=1;i<=n;i++)  //求連通塊 
49         if(!dfn[i])
50             tarjan(i);
51     for(int i=1;i<=n;i++)
52         for(int j=last[i];j;j=e[j].next){  //記錄各連通塊出度 
53             int v=e[j].to;
54             if(belong[i]!=belong[v])
55                 cd[belong[i]]++;
56         }
57     int ans1=Bcnt,ans2=0,tmp;  //ans1計算愛心天使數,ans2求出度為0且為天使的連通塊數量 ,tmp記錄出度為0且為天使的連通塊編號 
58     for(int i=1;i<=Bcnt;i++)
59         if(cd[i]==0&&v[i]!=1){
60             ans2++;
61             tmp=i;   
62         }
63     for(int i=1;i<=Bcnt;i++)
64         if(v[i]==1)  //排除一個點的連通塊 
65             ans1--;
66     printf("%d\n",ans1);
67     if(ans2==1){  //只有一個出度為0且為天使才滿足情況 
68         for(int i=1;i<=n;i++)
69             if(tmp==belong[i])
70                 printf("%d ",i);
71     }
72     else printf("-1");
73     return 0;
74 }

【codevs2822】愛在心中