4 4 1 2 1 3 1 4 2 3 0 0
0
题意:求出给定图中所有桥的数量,减去缩点后的最长链,即为题中所求答案(实际不用缩点也可求)
思路参考于:http://blog.csdn.net/qq172108805/article/details/9564705
#include "stdio.h" //用到双连通分量和树形dp的思想 #include "string.h" #pragma comment(linker,"/STACK:102400000,102400000") //手动扩大栈区(不扩栈会运行错误) #define N 201000 #define M 1001000 struct node { int x,y; bool visit; //标记该边是否走过 int next; }edge[4*M]; int idx,head[N]; inline int MIN(int a,int b){ return a<b?a:b; } void Init() { idx=0; memset(head,-1,sizeof(head)); } void Add(int x,int y) { edge[idx].x = x; edge[idx].y = y; edge[idx].visit = false; //开始时所有边都未走过 edge[idx].next = head[x]; head[x] = idx++; } int n,m; int sum,temp; int low[N],dfn[N],time; int dp1[N],dp2[N]; void DFS(int x) { int i,y; dp1[x] = dp2[x] = 0; low[x] = dfn[x] = ++time; for(i=head[x]; i!=-1; i=edge[i].next) { if(edge[i].visit) continue; y = edge[i].y; edge[i].visit = edge[i^1].visit = true; if(!dfn[y]) //点y未被访问过 { DFS(y); low[x] = MIN(low[x],low[y]); if(low[y] > dfn[x]) sum++; //当前边为桥,sum++ temp = dp1[y]; if(low[y] > dfn[x]) temp++; if(temp > dp1[x]) { dp2[x] = dp1[x]; dp1[x] = temp; } else if(temp > dp2[x]) dp2[x] = temp; } else low[x] = MIN(low[x],dfn[y]); } } int main() { int i; int x,y; while(scanf("%d %d",&n,&m),n||m) { Init(); for(i=0; i<m; ++i) { scanf("%d %d",&x,&y); Add(x,y); Add(y,x); } sum = 0; //统计图中桥的条数 time = 1; memset(dfn,0,sizeof(dfn)); DFS(1); int dist=0; //记录图的双连通分量缩点后的最长直径(最长的桥的长度)(实际不用处理缩点) for(i=1; i<=n; ++i) { if(dist<dp1[i]+dp2[i]) //dp1[i]+dp2[i]为经过点i的最长路径的长度 dist = dp1[i]+dp2[i]; } printf("%d\n",sum - dist);//所有桥的条数减最长路径的桥数,即为答案 } return 0; }