#1183 : 连通性一·割边与割点
描述
还记得上次小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;
}