[CF962F]Simple Cycles Edges
题目
题解
首先应分析在什么情况下,一条边才只会包含在一个简单环里面。
如果两个环有公共边,对于这两个环的边分情况讨论:
- 对于公共边,这条边被左、右俩环同时包含,显然不符题意;
- 对于非公共边,首先他们分别属于自己的环,其次,他们又在一个最外围的大环上;
也就是说,如果两个环有公共边,那么这俩环上没有边是符合题意的。
那么我们的目的就很明确了——寻找独立的简单环的边数并输出其编号。
此处“独立”是指与其他环没有公共边。
那么,问题变成如何“寻找”独立环,分析独立环的特性——显然,点数等于边数,这是再显然不过的条件。
那么,我们可以将图中的点双全部找出来,对于每一个点双再分别判断点数是否等于边数即可。
为什么不找边双?显然两个简单环是可以存在公共点的(区分公共边),所以我们寻找的其实是割点而非桥,最简单的一个模型就是 \(8\) 字结构,在这种模型下边双就会出问题(CF 的数据应该是 test#8)。
代码
#include<cstdio>
#include<set>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
typedef long long LL;
// typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned uint;
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void read(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T read(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int maxn=100000;
const int maxm=100000;
struct edge{int to,nxt;}e[maxm*2+5];
int tail[maxn+5],ecnt=1;//从 1 开始
inline void add_edge(const int u,const int v){
e[++ecnt]=edge{v,tail[u]};tail[u]=ecnt;
e[++ecnt]=edge{u,tail[v]};tail[v]=ecnt;
}
int n,m;
inline void Init(){
n=read(1),m=read(1);
rep(i,1,m)add_edge(read(1),read(1));
}
int stk[maxn*3+5],st;
int dfn[maxn+5],low[maxn+5],idx;
int dcc_cnt;
set<int>nde[maxn+5],ege[maxn+5];
void tarjan(const int u,const int pre){
dfn[u]=low[u]=++idx;
erep(i,u)if(v^pre){
if(!dfn[v]){
stk[++st]=i>>1,stk[++st]=u,stk[++st]=v;
tarjan(v,u);
low[u]=Min(low[u],low[v]);
if(low[v]>=dfn[u]){
++dcc_cnt;
int n1,n2;
while(1){
nde[dcc_cnt].insert(n1=stk[st--]);
nde[dcc_cnt].insert(n2=stk[st--]);
ege[dcc_cnt].insert(stk[st--]);
if(n1==v && n2==u)break;
}
}
}else if(dfn[v]<dfn[u]){
stk[++st]=i>>1,stk[++st]=u,stk[++st]=v;
low[u]=Min(low[u],dfn[v]);
}
}
}
set<int>ans;
signed main(){
Init();
rep(i,1,n)if(!dfn[i])tarjan(i,0);
rep(i,1,dcc_cnt)if(nde[i].size()==ege[i].size())
ans.insert(ege[i].begin(),ege[i].end());
writc(ans.size(),'\n');
for(int u:ans)writc(u,' ');
return 0;
}