hihoCoder 1183 连通性一·割边与割点(Tarjan求割点与割边)

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

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢失。为了避免再次出现这样的情况,学校决定对校园网络进行重新设计。

学校现在一共拥有N台服务器(编号1..N)以及M条连接,保证了任意两台服务器之间都能够通过连接直接或者间接的数据通讯。

当发生黑客攻击时,学校会立刻切断网络中的一条连接或是立刻关闭一台服务器,使得整个网络被隔离成两个独立的部分。

举个例子,对于以下的网络:

每两个点之间至少有一条路径连通,当切断边(3,4)的时候,可以发现,整个网络被隔离为{1,2,3},{4,5,6}两个部分:

若关闭服务器3,则整个网络被隔离为{1,2},{4,5,6}两个部分:

小Hi和小Ho想要知道,在学校的网络中有哪些连接和哪些点被关闭后,能够使得整个网络被隔离为两个部分。

在上面的例子中,满足条件的有边(3,4),点3和点4。

提示:割边&割点

输入

第1行:2个正整数,N,M。表示点的数量N,边的数量M。1≤N≤20,000, 1≤M≤100,000

第2..M+1行:2个正整数,u,v。表示存在一条边(u,v),连接了u,v两台服务器。1≤u<v≤N

保证输入所有点之间至少有一条连通路径。

输出

第1行:若干整数,用空格隔开,表示满足要求的服务器编号。从小到大排列。若没有满足要求的点,该行输出Null

第2..k行:每行2个整数,(u,v)表示满足要求的边,u<v。所有边根据u的大小排序,u小的排在前,当u相同时,v小的排在前面。若没有满足要求的边,则不输出

样例输入
6 7
1 2
1 3
2 3
3 4
4 5
4 6
5 6
样例输出
3 4
3 4

题目链接:hicoCoder 1183

验证一下自己以往的代码是否正确的题目,不过这题十分坑爹,若没有割点,要输出 Null ,WA半天查了题解发现他们都有输出这句……加上去就过了,怪自己眼神不好

第1行:若干整数,用空格隔开,表示满足要求的服务器编号。从小到大排列。若没有满足要求的点,该行输出Null

割点判断:

1、当前点为你一开始tarjan的起始点(即你进入某颗dfs搜索树的第一个点)且它的儿子有两个,前者多传递一个参数就能解决,后者用一个son变量记录这个节点的搜索子树有几颗。

2、当前点不是起始点,但儿子节点的low值大于当前点的dfn[u]值,即儿子边无法返回即$low[v]>=dfn[u]$。

割边判断条件:

比较简单只需要$low[v]>dfn[u]$即可,跟割点一样无法返回,但是由于是针对边的,肯定不能加等于号,代码中加入了重边判断,题目有没有重边不清楚,但是肯定这样写好一点

代码(sublime代码格式化真是好用):

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 20010;
const int M = 100010;
struct edge
{
	int to, nxt, id;
};
edge E[M << 1];
int head[N], tot;
int low[N], dfn[N], st[N], top, ts;
bool ins[N], cut[N];
vector<pii>bridge;

void init()
{
	CLR(head, -1);
	tot = 0;
	CLR(low, 0);
	CLR(dfn, 0);
	top = ts = 0;
	CLR(ins, false);
	bridge.clear();
	CLR(cut, false);
}
inline void add(int s, int t, int id)
{
	E[tot].to = t;
	E[tot].id = id;
	E[tot].nxt = head[s];
	head[s] = tot++;
}
void Tarjan(int u, int id, const int &rt)
{
	low[u] = dfn[u] = ++ts;
	st[top++] = u;
	ins[u] = 1;
	int v, i;
	int son = 0;
	for (i = head[u]; ~i; i = E[i].nxt)
	{
		v = E[i].to;
		if (E[i].id == id)
			continue;
		if (!dfn[v])
		{
			++son;
			Tarjan(v, E[i].id, rt);
			low[u] = min(low[u], low[v]);

			if (low[v] > dfn[u])
				bridge.push_back(pii(min(u, v), max(u, v)));

			if (u == rt && son > 1)
				cut[u] = 1;
			else if (u != rt && low[v] >= dfn[u])
				cut[u] = 1;
		}
		else if (ins[v])
			low[u] = min(low[u], dfn[v]);
	}
	if (low[u] == dfn[u])
	{
		do
		{
			v = st[--top];
			ins[v] = 0;
		} while (u != v);
	}
}
int main(void)
{
	int n, m, a, b, i;
	while (~scanf("%d%d", &n, &m))
	{
		init();
		for (i = 0; i < m; ++i)
		{
			scanf("%d%d", &a, &b);
			add(a, b, i);
			add(b, a, i);
		}
		for (i = 1; i <= n; ++i)
			if (!dfn[i])
				Tarjan(i, -1, i);
		int first = 0;
		for (i = 1; i <= n; ++i)
			if (cut[i])
				printf("%s%d", ++first == 1 ? "" : " ", i);
		if (!first)
			printf("Null");
		putchar(‘\n‘);
		int sz = bridge.size();
		sort(bridge.begin(), bridge.end());
		for (i = 0; i < sz; ++i)
			printf("%d %d\n", bridge[i].first, bridge[i].second);
	}
	return 0;
}
时间: 2024-10-17 09:36:13

hihoCoder 1183 连通性一·割边与割点(Tarjan求割点与割边)的相关文章

tarjan求割点割边的思考

这个文章的思路是按照这里来的. 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 一,根节点如果有两颗及以上子树,它就是割点.这个应该说是显然的. 二,对于普通的结点a,如果它递归树的子树中,有任意节点b的low[b]<dfn[a],那么它就不是割点,反之则是割点. 我们先来证明如果low[b]<dfn[a],a一定不是割点.low[b]<dfn[a]说明有一个结点,通过非树枝边可以访问到a以前的结点,那么显然去掉a以后,b依然与a以上的递归树联通,a不是割

UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u],则边(u,v)为桥(封死在子树内),不操作. 求割点时,枚举所有与当前点u相连的点v: 1.是重边: 忽略 2.是树边: Tarjan(v),更新low[u]=min(low[u],low[v]); 子树个数cnt+1.如果low[v] >= dfn[u],说明是割点,割点数+1 3.是回边: 更新lo

[POJ1144][BZOJ2730]tarjan求割点

求割点 一种显然的n^2做法: 枚举每个点,去掉该点连出的边,然后判断整个图是否联通 用tarjan求割点: 分情况讨论 如果是root的话,其为割点当且仅当下方有两棵及以上的子树 其他情况 设当前节点为u,一个儿子节点为v 存在low[v]>=dfn[u],也就是说其儿子节点v能连到的最前面的点都在u的下面 也就是当u断开的时候,u之前的点与以v为根的子树必然分成两个独立的块 那么这个时候u就是割点 Network A Telephone Line Company (TLC) is estab

poj1144 tarjan求割点

poj1144 tarjan求割点 额,算法没什么好说的,只是这道题的读入非常恶心. 还有,理解tarjan一定要用递归树,配合横边回边前边树边等来想.. #include <cctype> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=100, maxm=5000; struct Graph{ struct Edge

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最

poj1144 tarjan求割点 裸题

Network Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11684   Accepted: 5422 Description A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N

poj1144 Network【tarjan求割点】

转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4319585.html   ---by 墨染之樱花 [题目链接]http://poj.org/problem?id=1144 [题目描述](半天才看明白...)给图求割点个数 [思路]直接套求割点的模板即可,就是要注意输入比较坑.代码见下,附注释 #include <iostream> #include <ios> #include <iomanip> #includ

uoj 67 新年的毒瘤 tarjan求割点

#67. 新年的毒瘤 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/67 Description 辞旧迎新之际,喜羊羊正在打理羊村的绿化带,然后他发现了一棵长着毒瘤的树. 这个长着毒瘤的树可以用 n 个结点 m 条无向边的无向图表示.这个图中有一些结点被称作是毒瘤结点,即删掉这个结点和与之相邻的边之后,这个图会变为一棵树.树也即无简单环的无向连通图. 现在给你这个无向图,喜羊羊请你帮他求出所有毒瘤结点. I

UVA - 315 Network(tarjan求割点的个数)

题目链接:https://vjudge.net/contest/67418#problem/B 题意:给一个无向连通图,求出割点的数量.首先输入一个N(多实例,0结束),下面有不超过N行的数,每行的第一个数字代表后面的都和它存在边,0表示行输入的结束. 题解:简单的求割点模版,所谓割点就是去掉这一个点还有于这个点链接的边之后使得原来的图连通块增加. 由于这是模版题代码会加上注释. #include <iostream> #include <cstring> using namesp