题目地址:ZOJ 2588
因为数组开小了而TLE了。。这题就是一个求无向连通图最小割边。只要判断dfn[u]是否<low[v],因为low指的当前所能回到的祖先的最小标号,加入low[v]大于dfn[u]时,说明v无法通过其他边回到u之前的点,也就是说v如果想要回到u的祖先点,必须要经过u点,那这条边很明显就是一条割边。这题还要去重边,假如有重边的话,说明怎么销毁哪条边总能通过另一条边,所以只要有重边,说明这两点之间没有割边。
代码如下;
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include <set> #include <algorithm> using namespace std; int head[20020], cnt, index1, ans; int low[20103], dfn[20103], road[20103]; struct node { int num, u, v, next, tag; } edge[220000]; void add(int num, int u, int v) { int i; for(i=head[u]; i!=-1; i=edge[i].next) { if(edge[i].v==v) break; } if(i!=-1) { edge[i].tag=1; return ; } edge[cnt].tag=0; edge[cnt].num=num; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void tarjan(int u, int fa) { low[u]=dfn[u]=++index1; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(v==fa) continue ; if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<low[v]&&!edge[i].tag) { road[++ans]=edge[i].num; //printf("%d %d %d %d\n",u,v,dfn[u],low[v]); } } else low[u]=min(low[u],dfn[v]); } } void init() { memset(head,-1,sizeof(head)); cnt=0; index1=ans=0; memset(dfn,0,sizeof(dfn)); } int main() { int t, n, m, u, v, i, j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(); for(i=1; i<=m; i++) { scanf("%d%d",&u,&v); add(i,u,v); add(i,v,u); } tarjan(1,0); printf("%d\n",ans); if(ans) { sort(road+1,road+ans+1); for(i=1; i<ans; i++) { printf("%d ",road[i]); } printf("%d\n",road[ans]); } if(t!=0) printf("\n"); } return 0; }
时间: 2024-10-23 21:11:08