D7 割点 割边 强连通分量
今天几道是模板题;
第一道:(粘不了链接呜呜呜)
题目描述
n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接。因电子设备容易损坏,需给通讯点配备备用交换机。
但备用 交换机数量有限,不能全部配备,只能给部分重要城市配置。
于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备 用交换机。
请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换机城市的编号。
友情提示:图论常见的坑点,重边,自环,还有对本题来说的不连通
输入格式
第一行,一个整数n,表示共有n个城市(2<=n<=20000)
下面有若干行(<=60000):每行2个数a、b,a、b是城市编号,表示a与b之间有直接通讯线路。
输出格式
第一行,1个整数m,表示需m个备用交换机。
下面有m行,每行有一个整数,表示需配备交换机的城市编号。
输出顺序按编号由小到大。如果没有城市需配备备用交换机则输出0。
题解:对于中心交换器a,b;只需以a为根节点进行遍历,寻找割点的子树中是否含有b节点;如果有,则是一种可行解;
#include<bits/stdc++.h>
using namespace std;
#define N 500001
struct gg
{
int y,next;
}a[N];
inline int read()
{
int x=,f=;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ch=-;ch=getchar();}
while(isdigit(ch)) {x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;
}
int n,m,ans[N<<],lin[N<<],tot,cnt,dfn[N<<],low[N<<];
int root;
inline void add(int x,int y)
{
a[++tot].y=y;
a[tot].next=lin[x];
lin[x]=tot;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
int flag=;
for(int i=lin[x];i;i=a[i].next)
{
int y=a[i].y;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(x!=root||flag>) ans[x]=;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
freopen("gd.in","r",stdin);
freopen("gd.out","w",stdout);
n=read();
tot=;
memset(dfn,,sizeof(dfn));
memset(lin,,sizeof(lin));
memset(low,,sizeof(low));
memset(ans,,sizeof(ans));
int x,y;
while(scanf("%d%d",&x,&y)!=EOF)
{
if(x==y) continue;
add(x,y);add(y,x);
}
for(int i=;i<=n;i++)
if(dfn[i]==) root=i,tarjan(i);
int k=;
for(int i=;i<=n;i++)
if(ans[i]) ++k;
cout<<k<<endl;
for(int i=;i<=n;i++)
if(ans[i]) cout<<i<<endl;
return ;
}
第二题:LUOGU5058
摘自:https://www.luogu.org/blog/da32s1da/solution-p5058
首先非常明显的是,只能把服务器建在割点上,因为只有这样,才能捕获到全部的数据。
考虑如何求x,y两点之间的必经的割点。
很明显需要满足4个条件
考虑我们有一个u点,它连了一个v点,那么u点需要满足4个条件。
- u不是起点终点。因为题目要求在中间服务器上建嗅探器。
- u是割点。
- 终点(y)的dfn应该大于等于v点的dfn,因为要确保终点在v点或之后被访问到,即u点为必经的点。
- 终点(y)的low应该大于等于u点的dfn,因为要确保终点必须要经过u点。
剩下的没什么了,板子
注意我们从x点开始tarjan,就不用看x点是不是割点了。
#include<bits/stdc++.h>
using namespace std;
#define N 500001
inline int read()
{
int x=,f=;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;
}
int n,m,tot,lin[N],dfn[N],low[N],k,cnt,root,x,y;
int ans=0x7fffffff;
struct gg
{
int y,next;
}a[N<<];
void add(int x,int y)
{
a[++tot].y=y;
a[tot].next=lin[x];
lin[x]=tot;
}
void tarjan(int u)
{
dfn[u]=low[u]=++cnt;
for(int i=lin[u];i;i=a[i].next)
{
int v=a[i].y;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
if(u!=x&&u!=y)
if(dfn[u]<=low[v]&&dfn[v]<=dfn[y]&&low[y]>=dfn[x])
ans=min(ans,u);
}
else low[u]=min(low[u],dfn[v]);
}
}
int main()
{
n=read();
memset(dfn,,sizeof(dfn));
memset(lin,,sizeof(lin));
while(cin>>x>>y&&x!=&&y!=)
add(x,y),add(y,x);
x=read();y=read();
tarjan(x);
if(ans!=0x7fffffff) cout<<ans<<endl;
else cout<<"No solution"<<endl;
return ;
}
第三题:LUOGU P3469
#include<bits/stdc++.h>
using namespace std;
#define N 500001
inline int read()
{
int x=,f=;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;
}
int lin[N],dfn[N],low[N],tot,n,m,x,y,cnt,size[N],cut[N];
long long ans[N];
struct gg
{
int y,next;
}a[N<<];
void add(int x,int y)
{
a[++tot].y=y;
a[tot].next=lin[x];
lin[x]=tot;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
size[x]=;
int flag=,sum=;
for(int i=lin[x];i;i=a[i].next)
{
int y=a[i].y;
if(!dfn[y])
{
tarjan(y);
size[x]+=size[y];
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
ans[x]+=(long long)size[y]*(n-size[y]);
sum+=size[y];
if(x!=||flag>) cut[x]=;
}
}
else low[x]=min(low[x],dfn[y]);
}
if(cut[x]) ans[x]+=(long long)(n-sum-)*(sum+)+(n-);
else ans[x]=*(n-);
}
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
n=read();m=read();
tot=;
for(int i=;i<=m;i++)
{
int x,y;
x=read();y=read();
if(x==y) continue;
add(x,y),add(y,x);
}
tarjan();
for(int i=;i<=n;i++)
printf("%lld\n",ans[i]);
return ;
}
第四题:
题目描述
天凯是苏联的总书记。苏联有n个城市,某些城市之间修筑了公路。任意两个城市都可以通过公路直接或者间接到达。 天凯发现有些公路被毁坏之后会造成某两个城市之间无法互相通过公路到达。这样的公路就被称为dangerous pavement。 为了防止美帝国对dangerous pavement进行轰炸,造成某些城市的地面运输中断,天凯决定在所有的dangerous pavement驻扎重兵。可是到底哪些是dangerous pavement呢?你的任务就是找出所有这样的公路。
输入格式
第一行n,m(1<=n<=100000, 1<=m<=300000),分别表示有n个城市,总共m条公路。
以下m行每行两个整数a, b,表示城市a和城市b之间修筑了直接的公路。
输出格式
输出有若干行。每行包含两个数字a,b(a < b),表示 < a,b >是dangerous pavement。请注意:输出时,所有的数对< a,b>必须按照a从小到大排序输出;如果a相同,则根据b从小到大排序。
寻找割边输出,最后输出处理一下,并且保证题目要求的顺序;
#include<bits/stdc++.h>
using namespace std;
#define N 500001
inline int read()
{
int x=,f=;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;
}
struct gg
{
int y,next;
}a[N<<];
struct pink
{
int x,y;
}b[N<<];
bool mycmp(pink a,pink b)
{
if(a.x!=b.x) return a.x<b.x;
else return a.y<b.y;
}
int lin[N*],dfn[N*],low[N*],tot,cnt,n,m,x,y,bridge[N*];
inline void add(int x,int y)
{
a[++tot].y=y;
a[tot].next=lin[x];
lin[x]=tot;
}
inline void tarjan(int x,int in_edge)
{
dfn[x]=low[x]=++cnt;
for(int i=lin[x];i;i=a[i].next)
{
int y=a[i].y;
if(!dfn[y])
{
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bridge[i]=bridge[i^]=;
}
else if(i!=(in_edge^))
low[x]=min(low[x],dfn[y]);
}
}
int main()
{
freopen("danger.in","r",stdin);
freopen("danger.out","w",stdout);
n=read();m=read();
memset(lin,,sizeof(lin));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
tot=;
for(int i=;i<=m;i++)
{
x=read();y=read();
add(x,y);add(y,x);
}
for(int i=;i<=n;i++)
if(dfn[i]==) tarjan(i,);
int k=;
for(int i=;i<=tot;i+=)
if(bridge[i])
{
k++;
if(a[i].y<a[i^].y)
b[k].x=a[i].y,b[k].y=a[i^].y;
else b[k].x=a[i^].y,b[k].y=a[i].y;
}
sort(b+,b++k,mycmp);
for(int i=;i<=k;i++)
cout<<b[i].x<<' '<<b[i].y<<endl;
return ;
}
第五题:luoguP1726
#include<bits/stdc++.h>
#define N 100500
using namespace std;
template<typename T>inline void read(T &x)
{
x=;
register int f=;
register char ch=getchar();
while (!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
x*=f;
}
struct gg
{
int next,y;
}e[N<<];
int lin[N<<],dfn[N],low[N],cnt,tot,hl,n,m,ans[N];
int du[N],id[N],all[N];
bool v[N];
stack<int>s;
inline void add(int x,int y)
{
cnt++;
e[cnt].y=y;
e[cnt].next=lin[x];
lin[x]=cnt;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
s.push(x);v[x]=true;
for(int i=lin[x];i;i=e[i].next)
{
int u=e[i].y;
if(!dfn[u])
{
tarjan(u);
low[x]=min(low[x],low[u]);
}
else if(v[u]) low[x]=min(low[x],dfn[u]);
}
int k;
if(low[x]==dfn[x])
{
++hl;
do
{
k=s.top();s.pop();
v[k]=false;
id[k]=hl;all[hl]++;
}while(x!=k);
}
}
int main()
{
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
read(n);read(m);
int a,b,c;
for(int i=;i<=m;i++)
{
read(a);read(b);read(c);add(a,b);
if(c==) add(b,a);
}
for(int i=;i<=n;i++)
if(!dfn[i]) tarjan(i);
int t=,dcc;
for(int i=;i<=hl;i++)
{
if(t<all[id[i]])
{dcc=i;t=all[id[i]];}
}
cout<<t<<endl;
int k=;
for(int j=;j<=n;j++)
{
if(id[j]==id[dcc])
ans[++k]=j;
}
cout<<ans[];
for(int i=;i<=k;i++)
cout<<' '<<ans[i];
return ;
}
D7 割点 割边 强连通分量的更多相关文章
- POJ1523 Tarjan求割点以及删除割点之后强连通分量的数量
题目链接:http://poj.org/problem?id=1523 SPF:A Single Point of Failure也就是割点(一个点导致网络之间的不连通),由于给出的图是无向图,所以只 ...
- 【学习整理】Tarjan:强连通分量+割点+割边
Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量. 算法可以在 ...
- tarjan算法(割点/割边/点连通分量/边连通分量/强连通分量)
tarjan算法是在dfs生成一颗dfs树的时候按照访问顺序的先后,为每个结点分配一个时间戳,然后再用low[u]表示结点能访问到的最小时间戳 以上的各种应用都是在此拓展而来的. 割点:如果一个图去掉 ...
- tarjan算法(强连通分量 + 强连通分量缩点 + 桥(割边) + 割点 + LCA)
这篇文章是从网络上总结各方经验 以及 自己找的一些例题的算法模板,主要是用于自己的日后的模板总结以后防失忆常看看的, 写的也是自己能看懂即可. tarjan算法的功能很强大, 可以用来求解强连通分量, ...
- Tarjan 强连通分量 及 双联通分量(求割点,割边)
Tarjan 强连通分量 及 双联通分量(求割点,割边) 众所周知,Tarjan的三大算法分别为 (1) 有向图的强联通分量 (2) 无向图的双联通分量(求割点,桥) ...
- 小结:双连通分量 & 强连通分量 & 割点 & 割边
概要: 各种dfs时间戳..全是tarjan(或加上他的小伙伴)无限膜拜tarjan orzzzzzzzzz 技巧及注意: 强连通分量是有向图,双连通分量是无向图. 强连通分量找环时的决策和双连通的决 ...
- Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】
一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...
- (转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个 ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
随机推荐
- Hystrix入门与分析(一):初识Hystrix
在以前的文章中,我们介绍过使用Gauva实现限流的功能,现在我们来了解一下如何在服务框架中实现熔断和降级的方法. 简介Hystrix 大型系统架构的演进基本上都是这样一个方向:从单体应用到分布式架构. ...
- asp.net mvc 路由检测工具
初学mvc,路由搞不清楚,可以通过一款插件 查看匹配的路由. 工具名<RouteDebugger> 可以在nuget中查询RouteDebugger后,安装.或者在控制台进行安装: pm& ...
- Centos6.8 安装spark-2.3.1 以及 scala-2.12.2
一.Spark概述 Spark 是一个用来实现快速而通用的集群计算的平台. 在速度方面,Spark 扩展了广泛使用的 MapReduce 计算模型,而且高效地支持更多计算模式,包括交互式查询和流 ...
- java.io.UTFDataFormatException: encoded string too long:
java.io.UTFDataFormatException: encoded string too long: 259553 bytes 按如下修改可避开此问题. - output.writeUTF ...
- ubuntu安装sublime-text
按照网上的教程, wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - sudo apt ...
- Vue事件总线(eventBus)$on()会多次触发解决办法
项目中使用了事件总线eventBus来进行两个组件间的通信, 使用方法是是建立eventBus.js文件,暴露一个空的Vue实例,如下: import Vue from 'vue'export def ...
- mysql 时间戳的使用!
时间转时间戳方法: unix_timestamp() 记录时间戳的类型: bigint 时间戳转时间的方法:from_timestamp() 感谢水哥给的截图!
- debian使用nginx创建静态文件存储
vim /etc/nginx/sites-available/default 在server下添加 location ~ .*\.(gif|jpg|jpeg|png)$ { expires 24h; ...
- linux sftp远程上传文件
1.打开xshell 点击“新建文件传输”,如下图: 中间可能会出现下面的提示框,直接关掉即可: 2.切换到远程你要传输文件的目的地 命令:cd 你的路径 3.切换到本地文件所在目录 命令:lcd ...
- 1、vue 笔记之 组件
1.组件个人理解: <组件>是页面的一部分,将界面切分成部分,每部分称为 <组件> 2.组件化思想: //2.1.定义一个全局的组件,组件支持‘驼峰命名 ...