题意:
给出一幅n个点m条边的连通图 求图中有几个点双连通分量
并输出每条边所在点双连通分量中所有边的编号最小边的编号
代码:
#include<iostream> #include<cstdio> #include<cstring> #define maxn 20050 #define maxm 200050 using namespace std; struct node{ int id,to,next; }edge[maxm]; int head[maxn]; int s; int num,dfn[maxn],low[maxn]; int sta[maxm],top; int belong[maxm],temp[maxm],block,vis[maxn*5]; void Tarjan(int u,int pre) { dfn[u]=low[u]=++num; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(vis[edge[i].id]) //已标记的边不能通过同一条边的反向边再次访问 continue; if(!dfn[v]) { sta[top++]=edge[i].id; //边入栈 Tarjan(v,u); low[u]=min(low[v],low[u]); if(dfn[u]<=low[v]) { block++; int d=-1,s=0,minn=maxm; while(d!=edge[i].id) { d=sta[--top]; temp[s++]=d; vis[d]=1; //标记边 if(d<minn) minn=d; } for(int i=0;i<s;i++) belong[temp[i]]=minn; } } else if(v!=pre){ sta[top++]=edge[i].id; //边入栈 low[u]=min(dfn[v],low[u]); } } } void init() { memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(belong,0,sizeof(belong)); s=top=num=block=0; } int main() { // freopen("in.txt","r",stdin); int n,m,a,b; scanf("%d%d",&n,&m); init(); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); edge[s]={i,b,head[a]}; head[a]=s++; edge[s]={i,a,head[b]}; head[b]=s++; } Tarjan(1,-1); printf("%d\n",block); for(int i=1;i<=m;i++) printf("%d ",belong[i]); cout<<endl; return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-06 23:33:08