[CF962F]Simple Cycles Edges

Simple Cycles Edges

题解

很容易发现,一个简单环中不可能包含其它的边,即它的边数与点数必定相等,所以所有点双连通分量中边数与点数不等的必须舍去。因为如果其中间含有其它边,必定可以被分解成更多的简单环,其的边必定不可能符合条件。

如果利用边双连通的话,可能会被两个环交与一个点的情况卡掉,别问笔者是怎么知道的,而边双连通一定能被点双连通实现,所以改为求点双连通分量就可以得出打哪了。

由于要输出边的编号,可以利用set来实现统计与去重。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
typedef long long LL;
typedef unsigned long long uLL;
const LL mo=1e9+7;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,m,q,head[MAXN],tot,idx,d[MAXN];
int cnt,belong[MAXN];
int dfn[MAXN],low[MAXN],vis[MAXN];
int sta[MAXN*3],stak;
set<int>ans,Edge[MAXN],Node[MAXN];
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
int add(int x,int y){return x+y>=mo?x+y-mo:x+y;}
void tarjan(int u,int fa){
	dfn[u]=low[u]=++idx;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			sta[++stak]=i>>1;sta[++stak]=u;sta[++stak]=v;
			tarjan(v,u);low[u]=min(low[u],low[v]);
			if(dfn[u]<=low[v]){
				cnt++;int tu,tv,ti;
				do{
					Node[cnt].insert(tv=sta[stak--]);
					Node[cnt].insert(tu=sta[stak--]);
					Edge[cnt].insert(ti=sta[stak--]);
				}while(tu!=u||tv!=v);
			}
		}
		else if(dfn[v]<dfn[u]&&v!=fa){
			sta[++stak]=i>>1;sta[++stak]=u;sta[++stak]=v;				
			low[u]=min(low[u],dfn[v]);
		}
	}
}
signed main(){
	read(n);read(m);tot=1;
	for(int i=1;i<=m;i++){
		int u,v;read(u);read(v);
		addEdge(u,v);addEdge(v,u);
	}
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);
	for(int i=1;i<=cnt;i++){
		if(Edge[i].size()==Node[i].size())
			ans.insert(Edge[i].begin(),Edge[i].end());
		//printf("%d:%d %d\n",i,Edge[i].size(),Node[i].size());		
	}
	printf("%d\n",ans.size());
	for(auto u : ans)printf("%d ",u);
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值