时间限制:
10000ms
单点时限:
1000ms
内存限制:
256MB
-
6 7 1 2 1 3 2 3 3 4 4 5 4 6 5 6
样例输出
- 3 4 3 4
- tarjan算法。求割点与割边。。。
描述
还记得上次小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小的排在前面。若没有满足要求的边,则不输出
#include <iostream>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 20005
int flag[maxn],low[maxn],dfn[maxn],vis[maxn];
int n,m,scnt,j,root,fa[maxn];
vector<int>mat[maxn];
struct node
{
int s,e;
}bridge[maxn];
bool cmp(node a,node b)
{
if(a.s==b.s)
return a.e<b.e;
return a.s<b.s;
}
void dfs(int v)
{
int i,w,cnt=0;
scnt++;
vis[v]=1;
low[v]=dfn[v]=scnt;
for(i=0;i<mat[v].size();i++)
{
w=mat[v][i];
if(!vis[w])
{
cnt++;
fa[w]=v;
dfs(w);
low[v]=min(low[v],low[w]);
if(v==root&&cnt>1)//判断割点
flag[v]=1;
if(v!=root&&low[w]>=dfn[v])//判断割点
flag[v]=1;
if(low[w]>dfn[v])//判断割边
{
bridge[j].s=min(w,v);
bridge[j].e=max(w,v);
j++;
}
}
else if(fa[v]!=w)
low[v]=min(low[v],dfn[w]);
}
}
int main()
{
int i,a,b,c[maxn];
cin>>n>>m;
for(i=1;i<=n;i++)
mat[i].clear();
memset(flag,0,sizeof(flag));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(fa,0,sizeof(fa));
for(i=0;i<m;i++)
{
cin>>a>>b;
mat[a].push_back(b);
mat[b].push_back(a);
}
root=1;scnt=j=0;
dfs(root);
int f=0;
for(i=1;i<=n;i++)
{
if(flag[i]==1)
c[f++]=i;
}
sort(c,c+f);
sort(bridge,bridge+j,cmp);
if(f==0)
cout<<"Null\n";
else
{
for(i=0;i<f-1;i++)
cout<<c[i]<<" ";
cout<<c[i]<<endl;
for(i=0;i<j;i++)
cout<<bridge[i].s<<" "<<bridge[i].e<<endl;
}
return 0;
}