桥
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<map>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define debug printf("debug......\n");
#define pfd(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
const double eps=1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
const int maxn = 1e6+10;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0 , 0};
int n,m;
int low[maxn];//顶点的low值
int ids[maxn];//顶点的dfs次序
bool vis[maxn];//访问标记
int id;//dfs次序
vector<int> G[maxn];//存图
struct edge{
int u,v;
edge(int a, int b){u = a; v = b;}
bool operator < (const edge x) const{
if(u == x.u) return v < x.v;
return u < x.u;
}
};
vector<edge> bridge;//存答案
//
void dfs(int u, int pre){
vis[u] = 1;
low[u] = ids[u] = ++id;
for(int i=0; i<G[u].size(); i++){
int v = G[u][i];
if(v == pre) continue;
if(!vis[v]){
dfs(v , u);
low[u] = min(low[u] , low[v]);
//桥存在定理
if(ids[u] < low[v]){
int uu = u, vv = v;
//根据题意 这里需要把u调成小的
if(uu > vv) swap(uu , vv);
bridge.push_back(edge(uu,vv));
}
}
else{
low[u] = min(low[u] , ids[v]);
}
}
}
void findBrige(){
id = 0;
MS(low , 0);
MS(vis , 0);
bridge.clear();
rep(i,0,n-1){
if(!vis[i]) dfs(i, -1);
}
}
int main(){
while(sc(n)!=EOF){
//if(n == 0) break;
rep(i,0,n-1) G[i].clear();
rep(i,0,n-1){
int u,k,v;
scanf("%d (%d)",&u, &k);
while(k--){
sc(v);
G[u].push_back(v);
}
}
findBrige();
sort(bridge.begin(),bridge.end());
printf("%d critical links\n",bridge.size());
for(int i=0; i<bridge.size(); i++){
printf("%d - %d\n",bridge[i].u,bridge[i].v);
}
printf("\n");
}
return 0;
}