codeforces 962F Simple Cycles Edges

http://www.elijahqi.win/archives/3603
题意翻译
定义无向图中简单环为某几条边构成的最小环(即该环中不再包含更小的环),现给出n点m条边(n,m<=100000),求恰好被包含在一个(多了少了都不行)简单环中的边,第一行输出这些边个数,第二行根据输入顺序输出这些边编号.数据保证无重边自环,但不一定保证连通.

感谢 @cy1366371760 提供的翻译。

以前一直写点入栈的点双 这次yy一下边入栈 wa不停..

考虑把所有点双搞出来 然后判断每个点双是不是简单环如果是简单环统计答案即可

如果这个点双不是简单环 那么所有的边一定都包含在两个环

直接判断点数是否和边数相同即可

边入栈的时候需要特判时间戳 来判断该边i是否需要入栈

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e5+10;
struct node{
    int y,next,id;
}data[N<<1];
struct node1{
    int x,y,id;
}q[N];
int top,n,m,num,ans[N],h[N],dfn[N],low[N],size[N],s,b[N];vector<int> eg[N];
inline void tarjan(int x,int fa){
    dfn[x]=low[x]=++num;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa) continue;
        if (dfn[y]&&(dfn[y]<dfn[x]))q[++top]=(node1){x,y,data[i].id};
        if (!dfn[y]){
            q[++top]=(node1){x,y,data[i].id};
            tarjan(y,x);low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x]){
                ++s;node1 now;
                while(1){
                    now=q[top--];eg[s].push_back(now.id);
                    if (b[now.x]!=s) ++size[s],b[now.x]=s;
                    if (b[now.y]!=s) ++size[s],b[now.y]=s; 
                    if (now.x==x&&now.y==y) break;
                }
            }
        }else low[x]=min(low[x],dfn[y]);
    }
}
int main(){
    freopen("cf962f.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<=m;++i){
        int x=read(),y=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;data[num].id=i;
        data[++num].y=x;data[num].next=h[y];h[y]=num;data[num].id=i;
    }num=0;
    for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i,i);top=0;
    for (int i=1;i<=s;++i)
        if(eg[i].size()==size[i])
            for (int j=0;j<eg[i].size();++j) ans[++top]=eg[i][j];
    sort(ans+1,ans+top+1);printf("%d\n",top);
    for (int i=1;i<=top;++i) printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值