解题思路:

并查集 找环 未成环之前 看作一个树 

  用并查集找到环 两点 找的同时 建立一个 并查集树(自己瞎起的)找到两点后

   从两个点分别回到并查集的根节点经过的点标记上 这两个点单独经过的点(交点处除外)都是环上点 

  原文  欢迎访问 我的博客

注意事项:

参考代码:

#include<stdio.h>
#include<string.h>
#define N 1000002 
typedef long long ll;
ll a[N][3],f[N],bj[N],jd[N];
//ll BCJ(ll s)//并查集找根和更新 
//{  return f[s]==0?s:f[s]=BCJ(f[s]);
//}
ll BCJ(ll s)
{
 ll tem ,tx=s;
 while(f[tx]!=0)tx=f[tx];//并查集找根
 while(s!=tx)//并查集更新 
 { tem=f[s];
    f[s]=tx;
    s=tem;
 }
 return tx;
}
void BCJtree(ll x1,ll x2)//建立并查集树 
{
ll tx=x2,next=x1,last=jd[x1]; //两树合并  父变子 子变父 
while(next!=0)
{
jd[next]=tx;
tx=next;
next=last;
    last=jd[next];
}
}
void xzh(ll x)//寻找环节点 
{ ll last,r=x;bj[x]+=1;
while(1)
{if(jd[x]==0||bj[x]==2)break;//到并查集根节点或有重复节点 跳出 
  last=jd[x];
  bj[last]+=1;
  x=last;
}
if(bj[x]==2)// 重复节点 消重和去多余节点 
{ bj[x]=1;
  while(jd[x]!=0)
  {last=jd[x];
   bj[last]=0;
   x=last;
  }
}
}
 int main()
 { ll i,j,s1,s2,n,flag;
    while(scanf("%lld",&n)!=EOF)
    {  flag=0;
    memset(f,0,sizeof(f));
        memset(bj,0,sizeof(bj));
        memset(jd,0,sizeof(jd));
    for(i=1;i<=n;i++)
     { scanf("%lld%lld",&a[i][0],&a[i][1]);
        if(!flag)
        {  
        s1=BCJ(a[i][0]);
         s2=BCJ(a[i][1]);
        if(s1==s2)flag=i;//如果之前已经是同集合 这为环上两点 标记 
        else 
{
 if(!f[a[i][0]]) f[s1]=s2,BCJtree(a[i][0],a[i][1]);//a[i][0]节点为单集合或作为根节点的集合 
  else  f[s2]=s1,BCJtree(a[i][1],a[i][0]);// 含a[i][1]的集合接在含a[i][0]的集合 
  
}
        }
        
     }
    xzh(a[flag][0]);//从 A节点开始走 
    xzh(a[flag][1]);//从 B节点开始走 
      for(i=1;i<=n;i++) 
    if(bj[i]==1)printf("%lld ",i);
    printf("\n"); 
    }
 return 0;
 }


点赞(8)
 

0.0分

0 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论