hihocoder #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
tarjan算法。求割点与割边。。。
     
#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值