题意:给你一张无自环,无重边的无向图,定义简单环是环中的点只出现一次,求所有的只包含在一个简单环中的边。
题解:由于只能包含在一个简单环中,我们可以考虑tarjan缩点,然后我们对于以下这张图。
根据题意我们可以得到答案是6条边,因此我们需要通过点双连通分量缩点,而不是边双连通分量缩点。之后我们只要计算每一个点双连通分量中,点的数量与边的数量是否相同,就可以判断这个分量中的边是否满足条件。
点双连通分量内容,请移至博客:https://blog.csdn.net/acterminate/article/details/52526920
AC代码:
#include<stdio.h> #include<string.h> #include<iostream> #include<vector> #include<algorithm> #define N 100005 #define M 200005 using namespace std; struct edge { int to,next; edge(){} edge(int to,int next) { this->to=to; this->next=next; } }ed[M]; vector<int>vt[N]; int head[N],lnum,esum,index,top,bccnum; int dfn[N],low[N],mark[M],bj[N],st[M],belong[M],isCut[N],num[N]; pair<int,int>E[M]; void addline(int from,int to) { ed[lnum]=edge(to,head[from]); head[from]=lnum++; } void tarjan(int root,int fa){//有自环时不加自环的边 //点双连通缩点方法:清空路径,枚举E[]数组中存储的路径,建立双向边。 dfn[root]=low[root]=++index; //新点初始化 int child=0; //初始节点需要两个以上儿子且dfn[root]<=low[v] 才是割点 for(int i=head[root];~i;i=ed[i].next){ //遍历root指出去的边 int v=ed[i].to; if(mark[i]) continue; mark[i]=mark[i^1]=1; st[++top]=i;//边入栈,需注意此语句要放在判continue之后 if(!dfn[v]){ //如果v节点未去过,搜索v节点 child++; tarjan(v,root); low[root]=min(low[root],low[v]); //更新low值 if(dfn[root]<=low[v]){ isCut[root]=1; //此点是割点,需注意初始节点要有两个儿子 bccnum++;//注意这里是N++,建数组时要注意开至少两倍大 for(;;){ int j=st[top--]; //bj[]数组用来标记节点所属的bcc,割点会改变,无意义 //E[]存新图的边,esum是其数量,tarjan结束后建双向边 if(bj[ed[j].to]!=bccnum){ bj[ed[j].to]=bccnum; num[bccnum]++; E[++esum]=make_pair(ed[j].to,bccnum); } if(bj[ed[j^1].to]!=bccnum){ bj[ed[j^1].to]=bccnum; num[bccnum]++; E[++esum]=make_pair(ed[j^1].to,bccnum); } belong[(j>>1)+1]=bccnum;//标记边所属的bcc if(i==j)break; } } } else low[root]=min(low[root],dfn[v]); //与有向图区分,此处else不需要判别v节点是否在栈内 } if(root==fa && child<2)isCut[root]=0; //如果初始节点没有2个以上儿子,标记清0 } void init() { memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(mark,0,sizeof(mark)); memset(belong,0,sizeof(belong)); memset(isCut,0,sizeof(isCut)); top=0; lnum=0; index=0; bccnum=0; esum=0; } vector<int>ans; int main() { init(); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); addline(u,v); addline(v,u); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i); for(int i=1;i<=m;i++) vt[belong[i]].push_back(i); for(int i=1;i<=bccnum;i++) if(vt[i].size()==num[i]) for(int j=0;j<vt[i].size();j++) ans.push_back(vt[i][j]); sort(ans.begin(),ans.end()); printf("%d\n",ans.size()); for(int i=0;i<ans.size();i++) printf("%d ",ans[i]); printf("\n"); }