CF E42 F. Simple Cycles Edges // 点双分量记录边和点

题目

题意

给一个无向无自环无重边不连通的图,求所有简单环上的所有边。

思路

考虑点双。
点双跑出来只要判断每个块是否点数==边数。
栈里记录边起点和终点和编号,并且将反边也加入到栈里,就可以得到每个分量的边和点。

/*   Author : Rshs
 *   Data : 2019-10-02-14.51
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
vector<PII>g[MXN];
vector<int>nnn[MXN];
vector<int>bcc[MXN];
int ec[MXN];
/*                点双分量         */
int dfn[MXN],iscut[MXN],dfs_clock,bcc_cnt,bccno[MXN];
/*先序序号   割点否     时间戳    点双数量*/
struct no{
    int x,y,p;
};
stack<no>sk;
/* 暂存儿子*/
int tarjan(int u,int fa){

    int lowu=dfn[u]=++dfs_clock;
    int child=0;//记录u的儿子数
    for(auto ii:g[u]){
        int v=ii.FI;
        no E=no{u,ii.FI,ii.SE};
        if(!dfn[v]){
            sk.push(E);
            child++;
            int lowv=tarjan(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=dfn[u]){ //u是割点,u及v为根的子树是点双
                bcc_cnt++;
                iscut[u]=1;
                while(1){
                    no now=sk.top();sk.pop();
                    ec[bcc_cnt]++;nnn[bcc_cnt].push_back(now.p);
                    if(bccno[now.x]!=bcc_cnt){bcc[bcc_cnt].push_back(now.x);bccno[now.x]=bcc_cnt;}
                    if(bccno[now.y]!=bcc_cnt){bcc[bcc_cnt].push_back(now.y);bccno[now.y]=bcc_cnt;}
                    if(now.x==u&&now.y==v) break;
                }
            }
        }
        else if(v!=fa&&dfn[v]<dfn[u]){
            lowu=min(lowu,dfn[v]);  //连到了u的祖先(反向边
            sk.push(E);
        }
    }
    if(fa<0&&child==1) iscut[u]=0; //处理根结点
    return lowu;
}
void bccGet(int n){
    for(int i=1;i<=n;i++)bcc[i].clear(),dfn[i]=iscut[i]=0;
    while(!sk.empty())sk.pop();
    for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,-1);
}
int main(){
    int n,m;cin>>n>>m;
    for(int i=1;i<=m;i++){
        int sa,sb;scanf("%d %d",&sa,&sb);
        g[sa].push_back(MP(sb,i));g[sb].push_back(MP(sa,i));
    }
    bccGet(n);
    vector<int>ans;
    for(int i=1;i<=bcc_cnt;i++){
        if(SZ(bcc[i])!=ec[i]||ec[i]<=2)continue;
        for(auto j:nnn[i]) ans.push_back(j);
    }
    sort(ans.begin(),ans.end());
    cout<<ans.size()<<endl;
    for(auto i:ans)cout<<i<<' ';
    return 0;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值