HIHO #1183 : 连通性一·割边与割点

2024-08-30 20:08

本文主要是介绍HIHO #1183 : 连通性一·割边与割点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接

使用Tarjan算法计算无向图的割点和桥,提示讲解的也很清晰
需要注意的是,某一个割点可能会被多次计算,所以一般是先记录然后最后统一输出

1)按照题目的伪代码直接实现
2)稍微优化一下的,省一些空间

#include<bits/stdc++.h>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
#define LL long long
#define pb push_back
#define gcd __gcd#define For(i,j,k) for(int i=(j);i<k;i++)
#define lowbit(i) (i&(-i))
#define _(x) printf("%d\n",x)const int maxn = 2e5+200;
const int inf  = 1 << 28;int n,m;
vector<int> G[maxn];int fa[maxn],low[maxn],dfn[maxn];
bool vis[maxn];
set<int> cut;
set<pair<int,int> > bridge;
int counter;
void dfs(int u) {int child = 0;vis[u] = true;low[u]=dfn[u] = ++counter;for(int i=0; i<G[u].size(); i++) {int v = G[u][i];if(!vis[v]) {child++;fa[v] = u;dfs(v);low[u]=min(low[u],low[v]);if(fa[u]==-1&&child>1) {cut.insert(u);// 可能会被多次计算}if(fa[u]!=-1&&low[v]>=dfn[u]) {cut.insert(u);// 可能多次计算}if(low[v]>dfn[u]) {if(u<v)bridge.insert(make_pair(u,v));elsebridge.insert(make_pair(v,u));}} else if(v!=fa[u]) {low[u]=min(low[u],dfn[v]);}}
}void init(int n) {counter = 0;for(int i=0; i<=n; i++) {fa[i]=-1;vis[i]=dfn[i]=low[i]=0;G[i].clear();}cut.clear();bridge.clear();
}int main() {while(cin>>n>>m) {init(n);for(int i=0; i<m; i++) {int x,y;cin>>x>>y;G[x].pb(y);G[y].pb(x);}dfs(1);if(cut.empty()) {puts("Null");} else {for(set<int>::iterator i=cut.begin(); i!=cut.end(); i++) {if(i==cut.begin()) {cout<<*i;} else cout<<' '<<*i;}cout<<endl;}for(set<pair<int,int> >::iterator i=bridge.begin(); i!=bridge.end(); i++) {cout<<i->first<<' '<<i->second<<endl;}}return 0;
}

dfs加上一个参数,可以去掉vis,fa(parent)数组
搜索开始dfs(1,1)


#include<bits/stdc++.h>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
#define LL long long
#define pb push_back
#define gcd __gcd#define For(i,j,k) for(int i=(j);i<k;i++)
#define lowbit(i) (i&(-i))
#define _(x) printf("%d\n",x)const int maxn = 2e5+200;
const int inf  = 1 << 28;int n,m;
vector<int> G[maxn];int low[maxn],dfn[maxn];
set<int> cut;
set<pair<int,int> > bridge;
int counter;
void dfs(int u,int fa) {int child = 0;low[u]=dfn[u] = ++counter;for(int i=0; i<G[u].size(); i++) {int v = G[u][i];if(v==fa)continue;//避免(fa,u)这条树边的第二次访问if(!dfn[v]) {//时间戳刚好可以作为标记,时间戳从1开始child++;dfs(v,u);low[u]=min(low[u],low[v]);//树边更新if(u==fa&&child>1) {cut.insert(u);// 可能会被多次计算}if(u!=fa&&low[v]>=dfn[u]) {cut.insert(u);// 可能多次计算}if(low[v]>dfn[u]) {if(u<v)bridge.insert(make_pair(u,v));elsebridge.insert(make_pair(v,u));}} else {//上面continue语句后,这里就不用判断了low[u]=min(low[u],dfn[v]);//反向边更新}}
}void init(int n) {counter = 0;for(int i=0; i<=n; i++) {dfn[i]=low[i]=0;G[i].clear();}cut.clear();bridge.clear();
}int main() {while(cin>>n>>m) {init(n);for(int i=0; i<m; i++) {int x,y;cin>>x>>y;G[x].pb(y);G[y].pb(x);}dfs(1,1);if(cut.empty()) {puts("Null");} else {for(set<int>::iterator i=cut.begin(); i!=cut.end(); i++) {if(i==cut.begin()) {cout<<*i;} else cout<<' '<<*i;}cout<<endl;}for(set<pair<int,int> >::iterator i=bridge.begin(); i!=bridge.end(); i++) {cout<<i->first<<' '<<i->second<<endl;}}return 0;
}

这篇关于HIHO #1183 : 连通性一·割边与割点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121801

相关文章

图的割点、割线问题

图的割点问题 邻接矩阵表示图 package com.hyl.algorithm.other;import java.util.Arrays;import com.hyl.algorithm.search.base.SearchIntf;import com.hyl.algorithm.search.base.SearchIntfFactory;/*** 寻找图的割点* <p>** @aut

nc -s网络连通性测试

例如: nc -s 192.168.82.67 192.168.82.66 22 在这个命令中,您使用了nc(Netcat)工具来进行网络连接。下面是命令的详细说明: nc: 表示使用Netcat工具进行操作。-s 192.168.82.67: 指定源IP地址为192.168.82.67。这个参数让Netcat使用指定的IP地址进行网络连接,而不是默认的地址。192.168.82.66:

【ZOJ】2532 Internship 最小割——关键割边

传送门:【ZOJ】2532 Internship 题目分析:题目意思很明显,问你能否增加一条边的容量使得流量增加,就是让求关键割边。关键割边怎么求?首先按照题意建图跑一遍最小割。之后在残余网络上进行dfs,将从源点s出发能到的点标记为1,将从汇点t出发能到的点重标记为2。一条边为关键割边当且仅当它为正向边且弧头标记为1,弧尾标记为2。 PS:注意dfs的细节,s出发沿正向残余网络,t出发

HIHO #1190 : 连通性·四(点的双联通分量)

题目链接 点的双联通分量,不注意写出了一个bug,找了2个多小时= =,我的边存的是0开始的,然后ans数组一开始也是0,然后就是if的地方。。。。。 还是tarjan的算法,结合提示,这里需要存边,然后栈里面保存的是边,而不是点,这里我用边在边集es中的编号,作为边的标志 #include<bits/stdc++.h>using namespace std;#define cl(a,b

HIHO #1185 : 连通性·三

题目链接 先使用tarjan算法,计算强连通分量,进行缩点成DAG,然后在使用拓扑排序计算 tarjan中,我们只需要从1号节点计算,因为开始时在1号点。 建立新图的过程中,1号点不能到达的点也不用建立到新图里面 #include<bits/stdc++.h>using namespace std;#define cl(a,b) memset(a,b,sizeof(a))#defin

HIHO #1184 : 连通性二·边的双连通分量

题目链接 Tarjan算法,介绍可以看题目讲解,很好很清楚 无向图边的双联通分量的定义:对于一个无向图的子图,当删除其中任意一条边后,不改变图内点的连通性,这样的子图叫做边的双连通子图。而当子图的边数达到最大时,叫做边的双连通分量。 或者说,对于一个连通图,如果任意两点至少存在两条”边不重复”的路径。也就是要去每条边至少在一个简单的环中,也就是说所有的边都不是桥 同样是2个方法: 1)题

HIHO #1182 : 欧拉路·三(有向图 输出欧拉路径)

题目链接 A)建图是巧妙,使用边表示每一个数字,那么就是走完每一个边一次再回到起点,便是求欧拉回路 B)建图是有向图,建图需要注意,同时,输出的时候逆序输出 C)path保存的是完整的路径,输出的时候只需&1即可 #include<bits/stdc++.h>using namespace std;#define cl(a,b) memset(a,b,sizeof(a))#defin

HIHO #1181 : 欧拉路·二(fleury算法输出欧拉路径)

题目链接 伪代码 DFS(u):While (u存在未被删除的边e(u,v))删除边e(u,v)DFS(v)EndPathSize ← PathSize + 1Path[ PathSize ] ← u 点之间可能存在多条边,所以存边,然后标记每条边的标号,还是一个常见的存边的表示法 #include<bits/stdc++.h>using namespace std;#define c

P3388 【模板】割点(割顶)

~~~~~      P3388 【模板】割点(割顶) ~~~~~      总题单链接 割点的定义 ~~~~~      在一张无向图中,若删除一个点后连通块的数量会增加,那这个点就是割点。 怎么找割点 ~~~~~      按 d f s dfs dfs序 访问图上的每个点,每个点只访问一遍。 ~~~~~      先来看看时间戳的定义,若一个点的时间戳为 x x x,那

poj 1183 反正切函数的应用 数学推导

Description 反正切函数可展开成无穷级数,有如下公式  (其中0 <= x <= 1) 公式(1)  使用反正切函数计算PI是一种常用的方法。例如,最简单的计算PI的方法:  PI=4arctan(1)=4(1-1/3+1/5-1/7+1/9-1/11+...) 公式(2)  然而,这种方法的效率很低,但我们可以根据角度和的正切函数公式:  tan(a+b