题意:
给一个连通无向图..两点间可能有多条边...问加一条边后..桥最少能有多少个...
题解:
之前没写过tarjan求双联通分量的...练习赛的时候思路有点乱.再加上不断的爆栈..就搞不定了..
首先求双联通分量并缩点..如果题目能保证没有重边..做了无向图tarjan后每个点的low值就代表在哪个双连通分量里....但题目就是要绕一下..那么就先求出哪些边是桥..然后dfs染色..碰到桥不过去..就行..再将颜色相同的点缩成一个..做边....这时这个图就成了一颗树..题目是说加一条边后..要让桥最少..显然是要连接某两个度为1的点( 叶子节点或者说只有一个孩子的根节点)...链接这两点后..又出来一个双联通块..双联通块中的桥全部变成非桥..题目再次转化..求用双联通缩点后的树中的最长链..很典型的树形DP....
题目恶心的是会爆栈...真心不想手动写栈做dfs了...提供一种方法..再程序上方加入#pragma comment(linker,"/STACK:102400000,102400000") 用C++提交就行
Program:
#pragma comment(linker,"/STACK:102400000,102400000") //申请栈空间..用C++提交 #include<iostream> #include<stdio.h> #include<string.h> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #include<algorithm> #define ll long long #define eps 1e-5 #define oo 1000000007 #define pi acos(-1.0) #define MAXN 200005 #define MAXM 2000005 using namespace std; struct node { int x,y,id,next; }line[MAXM]; int Lnum,_next[MAXN],dfn[MAXN],low[MAXN],DfsIndex,dp[MAXN],tp[MAXN],tpnum,MM; bool used[MAXN],brige[MAXM]; void addline(int x,int y,int id) { line[++Lnum].next=_next[x],_next[x]=Lnum; line[Lnum].x=x,line[Lnum].y=y; line[Lnum].id=id; } void tarjan(int x,int id) { int y,k; dfn[x]=low[x]=++DfsIndex; for (k=_next[x];k;k=line[k].next) { if (line[k].id==id) continue; y=line[k].y; if (!dfn[y]) { tarjan(y,line[k].id); low[x]=min(low[x],low[y]); if (dfn[x]<low[y]) brige[k]=true; }else low[x]=min(low[x],dfn[y]); } return; } void dfs0(int x) { int k; tp[x]=tpnum; for (k=_next[x];k;k=line[k].next) if (!tp[line[k].y] && !brige[k]) dfs0(line[k].y); } void dfs(int x) { int y,k; dp[x]=0; used[x]=true; for (k=_next[x];k;k=line[k].next) { y=line[k].y; if (used[y]) continue; dfs(y); MM=max(MM,dp[x]+dp[y]+1); dp[x]=max(dp[x],dp[y]+1); } return; } int main() { int N,M,i; freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while (~scanf("%d%d",&N,&M) && ( N || M) ) { Lnum=0; memset(_next,0,sizeof(_next)); while (M--) { int x,y; scanf("%d%d",&x,&y); addline(x,y,M),addline(y,x,M); } memset(dfn,0,sizeof(dfn)); memset(brige,false,sizeof(brige)); DfsIndex=0; tarjan(1,-1); tpnum=0; memset(tp,0,sizeof(tp)); for (i=1;i<=N;i++) if (!tp[i]) { tpnum++; dfs0(i); } memset(_next,0,sizeof(_next)); int x,y,temp=Lnum; Lnum=0; for (i=1;i<=temp;i++) { x=tp[line[i].x],y=tp[line[i].y]; if (x==y) continue; addline(x,y,0); } memset(used,false,sizeof(used)); MM=0; dfs(1); printf("%d\n",tpnum-1-MM); } return 0; }