標籤:等級 string input amp uil nod 提示 ref time
2822 愛在心中
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 鑽石 Diamond
題目描述
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
資料範圍及提示
Data Size & Hint
各個測試點1s
-------------------------------------------------------------------------------------------------------------------
這道題的第一問,先用tarjan找出圖中所有的強聯通分量,找出兩個點及以上的強聯通分量即題中的愛心天使
那第二問呢?
我們需要一步縮點操作
就是把每個強聯通分量縮成一個點,建成另一個新的圖,而且這個圖肯定不帶環(樹或森林)
然後找出“愛心天使”中出度為0的點,從這個點開始遍曆新圖的反圖,倘若所有點都能夠遍曆到,則說明“這個愛心天使被其他所有人或愛心天使所愛”,否則就不行
那為什麼要找出度為0的點呢?
因為按題目的定義,這個愛心天使要能被所有點到達,又新圖中不帶環,所以不能有出度;從這裡也可以看出滿足條件的點最多隻有一個
AC代碼:
1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 10010 4 struct node{ 5 int to,next,fr; 6 }; 7 node e[maxn],tr[maxn]; 8 int n,m,belong[maxn],dfn[maxn],low[maxn],stack[maxn],cnt,pre[maxn],time,top,bcnt,pretr[maxn],wrt,size[maxn],dcnt,po[maxn],pref[maxn]; 9 bool instack[maxn],pd[maxn];10 void buildtr(int,int);11 void tarjan(int);12 void build(int,int);13 void dfs(int);14 int read();15 int main(){16 n=read();m=read();time=0;top=0;bcnt=0;wrt=0;dcnt=0;17 for(int i=1;i<=m;i++){18 int a=read(),b=read();19 build(a,b);20 }21 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);22 for(int i=1;i<=bcnt;i++) if(size[i]>1) po[++dcnt]=i;//第一問 23 printf("%d\n",dcnt); 24 cnt=0;25 for(int i=1;i<=m;i++)26 if(belong[e[i].to]!=belong[e[i].fr])27 buildtr(belong[e[i].fr],belong[e[i].to]);28 for(int i=1;i<=dcnt;i++)29 if(!pretr[po[i]]){30 memset(pd,0,sizeof(pd));31 dfs(po[i]);32 bool flag=true;33 for(int j=1;j<=bcnt;j++)34 if(!pd[j]){35 flag=false;36 break;37 }38 if(flag) wrt=po[i];39 break;//因為滿足條件的點只有一個,而且如果這個點不滿足,往後也不滿足,所以找到一個點出度為0的時候就可以退出了 ,40 }41 if(!wrt) printf("-1");42 else43 for(int i=1;i<=n;i++)44 if(belong[i]==wrt)45 printf("%d ",i);46 return 0;47 }48 void dfs(int x){49 pd[x]=1;50 for(int i=pref[x];i;i=tr[i].next) dfs(tr[i].to);51 }52 void buildtr(int x,int y){53 tr[++cnt].to=y;tr[cnt].next=pretr[x];pretr[x]=cnt;//新圖 54 tr[++cnt].to=x;tr[cnt].next=pref[y];pref[y]=cnt;//新圖的反圖 55 }56 void tarjan(int x){57 dfn[x]=low[x]=++time;58 instack[x]=1;stack[++top]=x;59 for(int i=pre[x];i;i=e[i].next){60 int to=e[i].to;61 if(!dfn[to]){62 tarjan(to);63 if(low[to]<low[x]) low[x]=low[to];64 }65 else if(instack[to]&&dfn[to]<low[x]) low[x]=dfn[to]; 66 }67 if(dfn[x]==low[x]){68 bcnt++;69 int k;70 do{71 k=stack[top--];72 instack[k]=0;73 belong[k]=bcnt;74 size[bcnt]++;75 }while(k!=x);76 }77 }78 void build(int x,int y){79 e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;e[cnt].fr=x;80 }81 int read(){82 int ans=0,f=1;char c=getchar();83 while(‘0‘>c||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}84 while(‘0‘<=c&&c<=‘9‘)ans=ans*10+c-48,c=getchar();return ans*f;85 }
tarjan
codevs 2822 愛在心中 tarjan(強聯通分量)