题目描述 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
芒果君:昨天又犯了一个错误让我开始怀疑人生。本来缩点做一次就够了结果我不小心没把函数上面那个循环删掉,怎么改都T了,最后还打了一个读入优化233333真是有病。然后这道题的话和那个(HAOI2006 受欢迎的牛)差不多,就多了一问。最近浪的太厉害tarjan还没学完,今天第一天课发现自己背包啥都不会了,so sad。
言归正传吧,题目意思就是求总共有多少容量大于1的强连通分量,一开始走一遍tarjan,求容量(own数组),求点所属强连通分量(集合jh数组),重构的部分我借鉴了hzw大佬,但只保留了一行用来判断有无初度。找答案的部分我认为值得学习一下,缩完点后,如果这个强连通分量被所有其它分量连接,那么它的出度为0且只能存在一个。因为你想,它肯定有入度,但如果它有出度,这就又和别的强连通了,不对吧。要是存在两个,它们都没有出度,互相否定了“被所有其他分量”这个条件,也不能成立。感觉需要理解一阵子而且我写的也很迷23333333 然后在这道题中还要注意,容量为1的分量是不符合条件的。
下面贴代码啦↓~
1 #include<bits/stdc++.h> 2 #define l 10010 3 using namespace std; 4 stack<int>S; 5 struct X{ 6 int v,next; 7 }e[50010]; 8 int n,m,ans,hl[l],HL[l],jh[l],own[l],vis1[l],vis2[l],low[l],dfn[l],cnt,num; 9 void add(int x,int y) 10 { 11 e[++cnt].v=y; 12 e[cnt].next=hl[x]; 13 hl[x]=cnt; 14 } 15 void tarjan(int x) 16 { 17 vis1[x]=vis2[x]=1; 18 dfn[x]=low[x]=++cnt; 19 S.push(x); 20 for(int i=hl[x];i;i=e[i].next){ 21 int to=e[i].v; 22 if(!vis1[to]){ 23 tarjan(to); 24 low[x]=min(low[x],low[to]); 25 } 26 else if(vis2[to]) low[x]=min(low[x],dfn[to]); 27 } 28 if(dfn[x]==low[x]){ 29 int now=-1; 30 num++; 31 while(now!=x){ 32 now=S.top(); 33 S.pop(); 34 vis2[now]=0; 35 jh[now]=num; 36 own[num]++; 37 } 38 } 39 } 40 void rebuild() 41 { 42 cnt=0; 43 for(int i=1;i<=n;++i) 44 for(int j=hl[i];j;j=e[j].next) 45 if(jh[i]!=jh[e[j].v]) HL[jh[i]]=++cnt; 46 } 47 int main() 48 { 49 cin>>n>>m; 50 for(int i=1;i<=m;++i){ 51 int x,y; 52 cin>>x>>y; 53 add(x,y); 54 } 55 for(int i=1;i<=n;++i) if(!vis1[i]) tarjan(i); 56 rebuild(); 57 for(int i=1;i<=num;++i) if(own[i]>1) ans++; 58 cout<<ans<<endl; 59 ans=0; 60 for(int i=1;i<=num;++i) 61 if(!HL[i]){ 62 if(ans||own[i]==1){ 63 cout<<"-1"<<endl; 64 return 0; 65 } 66 else ans=i; 67 } 68 for(int i=1;i<=n;++i) if(jh[i]==ans) cout<<i<<" "; 69 return 0; 70 }