题意:
给出一个图,问加一条边使得整个图桥变得最少。求最少的桥数。
题解:
双联通缩点成树,然后得到数的直径,那么我们要连接的点肯定是数直径的端点,那么只要知道直径就知道这两个端点之间边的个数,缩点完的边就是桥,于是最少的桥数=点数-1-数的直径(因为是树点数-1肯定就是边数了)。
无限爆栈。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<string> #include<vector> #include<queue> #include<map> #include<set> #define B(x) (1<<(x)) using namespace std; void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } typedef long long ll; const int oo=0x3f3f3f3f; const ll OO=1LL<<61; const int MOD=1000007; const int maxn=210000; const int maxm=2100000; struct EDGE{ int v,next; }E[maxm]; int head[maxn],tol; int low[maxn],dfn[maxn],instack[maxn],Stack[maxn]; int id[maxn]; int g_cnt,ID,top; vector<int>g[maxn]; int dis[maxn],vis[maxm]; void Init(){ memset(head,-1,sizeof head); memset(low,0,sizeof low); memset(dfn,0,sizeof dfn); memset(instack,0,sizeof instack); memset(vis,0,sizeof vis); g_cnt=ID=tol=top=0; } void add_edge(int u,int v){ E[tol].v=v; E[tol].next=head[u]; head[u]=tol++; } void Tarjan(int u){ dfn[u]=low[u]=++g_cnt; Stack[++top]=u; instack[u]=1; int v; for(int i=head[u];i!=-1;i=E[i].next){ v=E[i].v; if(!dfn[v]){ if(vis[i])continue; vis[i]=vis[i^1]=1; Tarjan(v); if(low[v]<low[u]) low[u]=low[v]; }else if(instack[v]&&dfn[v]<low[u]) low[u]=dfn[v]; } if(dfn[u]==low[u]){ ID++; do{ v=Stack[top--]; instack[v]=0; id[v]=ID; }while(u!=v); } } int bfs(int s){ for(int i=0;i<=ID;i++){ dis[i]=-1; vis[i]=0; } vis[s]=1; dis[s]=0; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!vis[v]){ dis[v]=dis[u]+1; vis[v]=1; q.push(v); } } } int ans=1; for(int i=1;i<=ID;i++){ if(dis[i]>dis[ans]) ans=i; } return ans; } void gao(int n){ for(int i=0;i<=ID;i++)g[i].clear(); for(int u=1;u<=n;u++){ for(int i=head[u];i!=-1;i=E[i].next){ int v=E[i].v; if(id[u]!=id[v]){ g[id[u]].push_back(id[v]); g[id[v]].push_back(id[u]); } } } printf("%d\n",ID-1-dis[bfs(bfs(1))]); } int main(){ //freopen("E:\\read.txt","r",stdin); int n,m,u,v; while(scanf("%d %d",&n,&m)!=EOF){ if(n==0&&m==0)break; Init(); for(int i=1;i<=m;i++){ scanf("%d %d",&u,&v); add_edge(u,v); add_edge(v,u); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); gao(n); } return 0; }