题目大意:给出一个连通图,求再一个边后,剩余的最少桥数。
题目思路:首先进行缩点得到重构后的图,求出重构后树的直径(通过两次BFS求出相距最远的两点间的距离),ans=重构图边数-树的直径
//#pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<vector> #include<iostream> #include<queue> #include<algorithm> #define MAXSIZE 200005 #define LL long long using namespace std; vector<vector<int> >G; vector<vector<int> >G2; int vis[MAXSIZE],low[MAXSIZE],dfn[MAXSIZE],pre[MAXSIZE],k,Time,n,m,ans,link; int dist[MAXSIZE],belong[MAXSIZE],step[MAXSIZE],Stuck[MAXSIZE],block; void Tarjan(int u,int fa) { low[u]=dfn[u]=++Time; pre[u]=fa; Stuck[k++]=u; int v,len=G[u].size(),op=0; for(int i=0;i<len;i++) { v=G[u][i]; if(!op && v==fa)//去重边 { op=1; continue; } if(!dfn[v]) { Tarjan(v,u); low[u]=min(low[u],low[v]); } else { low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]) { int temp; do{ temp=Stuck[--k]; belong[temp]=block; }while(temp!=u); block++; } } void Init() { memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(pre,0,sizeof(pre)); memset(belong,0,sizeof(belong)); memset(Stuck,0,sizeof(Stuck)); ans=0; Time=0; block=0; k=0; G.clear(); G2.clear(); G.resize(n+2); G2.resize(n+2); } int BFS(int s,int op) { int now,next; queue<int>Q; memset(step,-1,sizeof(step)); step[s]=0; Q.push(s); while(!Q.empty()) { now=Q.front(); Q.pop(); int len=G2[now].size(); for(int i=0;i<len;i++) { next=G2[now][i]; if(step[next]==-1) { step[next]=step[now]+1; Q.push(next); } } } if(op==0) return now; return step[now]; } int main() { int a,b; while(scanf("%d%d",&n,&m),n+m) { Init(); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } for(int i=1;i<=n;i++) { if(!dfn[i]) Tarjan(i,i); } for(int i=1;i<=n;i++) { int fa=pre[i]; if(belong[i] != belong[fa]) { G2[belong[i]].push_back(belong[fa]); G2[belong[fa]].push_back(belong[i]); } } //两边BFS求出树的直径 int s=BFS(0,0); int d=BFS(s,1); ans=block-d-1;// 重构后的图的边数等于点数-1,根据贪心策略再减去重构树的直径就是答案 printf("%d ",ans); } return 0; }