题意:求无向图的割边。
思路:tarjan算法求割边,访问到一个点,如果这个点的low值比它的dfn值大,它就是割边,直接ans++(之所以可以直接ans++,是因为他与割点不同,每条边只访问了一遍)。
需要注意的就是此处有多重边,题目中要求输出确定的不能被删除的边,而多重边的保留不是可以确定的,所以多重边都是不可以被保留的,我们可以在邻接表做一个flag的标记,判断他是不是多重边。
注意建图的时候数组应该是m × 2,因为这里是无向边,当心RE!
注意输出的时候编号是必须要拍好序再输出。
还有一个地方需要注意的就是应该选择高效的建图方式,我一开始看见给了5秒,就用邻接矩阵建了图,毕竟他能很好的记录重边,但交上去并不好使。。。又换了vector,结果莫名其妙的程序崩溃,我都开始怀疑人生了,想到zoj一向以严格刁钻出名,干脆换了比较高效的链式前向星,总算是过了,下面是代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 10010 int head[maxn],tot,dfn[maxn],low[maxn],ans_id[maxn*10],ans,cnt; struct EDGE { int to,nxt,flag,id; } edge[maxn*20]; void add_edge(int x,int y,int id) { bool mark = true; int pos = 0; for(int i = head[x]; i != -1; i = edge[i].nxt) { if(edge[i].to == y) { mark = false; pos = i; break; } } if(!mark) { edge[pos].flag = 1; return; } edge[cnt].to = y; edge[cnt].nxt = head[x]; edge[cnt].flag = 0; edge[cnt].id = id; head[x] = cnt++; } void tarjan(int x,int fa) { dfn[x] = low[x] = ++tot; for(int i = head[x]; i != -1; i = edge[i].nxt) { int y = edge[i].to; if(!dfn[y]) { tarjan(y,x); low[x] = min(low[x],low[y]); if(low[y] > dfn[x] && !edge[i].flag)///判断重边 { ans_id[ans++] = edge[i].id; } } else if(y != fa) low[x] = min(low[x],dfn[y]); } return; } int main() { int t,n,m; scanf("%d",&t); while(t--) { cnt = 0,tot = 0,ans = 0; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i = 1; i <= m; i++) { int x,y; scanf("%d%d",&x,&y); add_edge(x,y,i); add_edge(y,x,i); } memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); tarjan(1,-1); printf("%d\n",ans); sort(ans_id,ans_id + ans); if(ans != 0) { for(int i = 0; i < ans; i++) { i == 0 ? printf("%d",ans_id[i]) : printf(" %d",ans_id[i]); } printf("\n"); } if(t) puts(""); } return 0; }
时间: 2024-12-26 13:45:39