题意:给出若干组数据,每组数据的第一行为下面输入数据的行数。接下来依旧是每一行的第一个数代表的点与它后面的几个点直接相连,让你求出每一组数据所代表的图有多少条割边。
思路:套模板
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node
{
int from,to,next,flag;
}e[1500000];//和割点一样,仍用链式向前星存图
int cont,tot,cnt,n;
int head[150000];
int vis[150000];
int dfn[150000];
int low[150000];
int fa[150000];
void add(int from,int to)
{
e[cont].flag=0;
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}//链式向前星存图,比割点多了一个flag,用来标记是否为割边
void tarjan(int u,int pre)
{
dfn[u]=low[u]=++cnt;//第一次向下遍历
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v == pre)continue;//如果走了回头路,跳出此次循环
if(!dfn[v])
{
tarjan(v,u);
if(low[u]>low[v])low[u]=low[v];//更新最小时间戳
if(low[v]>dfn[u])
{
e[i].flag=1;
e[i^1].flag=1;
tot++;
}//满足该边为割边条件时,该边的两个端点的flag都标记为1
}
else if(low[u]>dfn[v])
low[u]=dfn[v];//更新最小时间戳
}
}
void Slove()
{
tot=0,cnt=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)if(vis[i]==0)tarjan(i,-1);
printf("%d critical links\n",tot);
vector<pair<int,int> >ans;
for(int u=1;u<=n;u++)
{
for(int i=head[u];i!=-1;i=e[i].next)
{
if(e[i].flag&&e[i].to>u)//一条边只输出一次,规定小的点在前,大的点在后
{
ans.push_back(make_pair(u,e[i].to));//将满足条件的边加入ans数组
}
}
}
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);//开始时为了套版子加了1,这里减去
}
printf("\n");
}
int main()
{
while(~scanf("%d",&n))
{
cont=0;
memset(head,-1,sizeof(head));
for(int i=0; i<n; i++)
{
int u,num;
scanf("%d (%d)",&u,&num);
u++;//套版子,版子都是从1开始,所以这里加1,最后输出结果再减1
while(num--)
{
int v;
scanf("%d",&v);
v++;//套版子,版子都是从1开始,所以这里加1,最后输出结果再减1
if(v<=u)continue;
add(u,v);
add(v,u);
}
}
Slove();
}
return 0;
}