UVA 796 - Critical Links (求橋)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=737
In a computer network a link L, which interconnects two servers, is considered critical if there are at least two servers A and B such that all network interconnection paths between A and B pass through L. Removing a critical link generates two disjoint sub-networks such that any two servers of a sub-network are interconnected. For example, the network shown in figure 1 has three critical links that are marked bold: 0 -1, 3 - 4 and 6 - 7.
Figure 1: Critical links
It is known that:
1.
the connection links are bi-directional;
2.
a server is not directly connected to itself;
3.
two servers are interconnected if they are directly connected or if they are interconnected with the same server;
4.
the network can have stand-alone sub-networks.
Write a program that finds all critical links of a given computer network.
Input
The program reads sets of data from a text file. Each data set specifies the structure of a network and has the format
The first line contains a positive integer (possibly 0) which is the number of network servers. The ne lines, one for each server in the network, are randomly ordered and show the way servers are connected. The line corresponding to server
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
/*
* 求 無向圖的割點和橋
* 可以找出割點和橋,求刪掉每個點後增加的連通塊。
* 需要注意重邊的處理,可以先用矩陣存,再轉鄰接表,或者進行判重
*/
const int MAXN = 10010;
const int MAXM = 100010;
struct Edge
{
int to,next;
bool cut;//是否為橋的標記
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int add_block[MAXN];//刪除一個點後增加的連通塊
int bridge;
void addedge(int u,int v)
{
edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false;
head[u] = tot++;
}
void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son = 0;
for(int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if(v == pre)continue;
if( !DFN[v] )
{
son++;
Tarjan(v,u);
if(Low[u] > Low[v])Low[u] = Low[v];
//橋
//一條無向邊(u,v)是橋,當且僅當(u,v)為樹枝邊,且滿足DFS(u)<Low(v)。
if(Low[v] > DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i^1].cut = true;
}
//割點
//一個頂點u是割點,當且僅當滿足(1)或(2) (1) u為樹根,且u有多於一個子樹。
//(2) u不為樹根,且滿足存在(u,v)為樹枝邊(或稱父子邊,
//即u為v在搜尋樹中的父親),使得DFS(u)<=Low(v)
if(u != pre && Low[v] >= DFN[u])//不是樹根
{
cut[u] = true;
add_block[u]++;
}
}
else if( Low[u] > DFN[v])
Low[u] = DFN[v];
}
//樹根,分支數大於1
if(u == pre && son > 1)cut[u] = true;
if(u == pre)add_block[u] = son - 1;
Instack[u] = false;
top--;
}
void solve(int N)
{
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(add_block,0,sizeof(add_block));
memset(cut,false,sizeof(cut));
Index = top = 0;
bridge = 0;
for(int i = 1;i <= N;i++)
if( !DFN[i] )
Tarjan(i,i);
printf("%d critical links\n",bridge);
vector<pair<int,int> >ans;
for(int u = 1;u <= N;u++)
for(int i = head[u];i != -1;i = edge[i].next)
if(edge[i].cut && edge[i].to > u)
{
ans.push_back(make_pair(u,edge[i].to));
}
sort(ans.begin(),ans.end());
//按順序輸出橋
for(int i = 0;i < ans.size();i++)
printf("%d - %d\n",ans[i].first-1,ans[i].second-1);
printf("\n");
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
//處理重邊
map<int,int>mapit;
inline bool isHash(int u,int v)
{
if(mapit[u*MAXN+v])return true;
if(mapit[v*MAXN+u])return true;
mapit[u*MAXN+v] = mapit[v*MAXN+u] = 1;
return false;
}
int main()
{
int n;
while(scanf("%d",&n) == 1)
{
init();
int u;
int k;
int v;
//mapit.clear();
for(int i = 1;i <= n;i++)
{
scanf("%d (%d)",&u,&k);
u++;
//這樣加邊,要保證正邊和反邊是相鄰的,建無向圖
while(k--)
{
scanf("%d",&v);
v++;//保證點從1開始;
//if(v <= u)continue;
//if(isHash(u,v))continue;
addedge(u,v);
addedge(v,u);
}
}
solve(n);
}
return 0;
}