hdu 4612 (双联通+树形DP)
加一条边后最少还有多少个桥,先Tarjan双联通缩点,
然后建树,求出树的直径,在直径起点终点加一条边去的桥最多,
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stack> #define N 200001 using namespace std; int belong[N],head[N],num,ins[N],n,dfs[N],low[N],idx,ans,num1; struct edge { int st,ed,next; }E[N*10],e[N*10]; void addedge(int x,int y) { E[num].st=x; E[num].ed=y; E[num].next=head[x]; head[x]=num++; } void Addedge(int x,int y) { e[num1].st=x; e[num1].ed=y; e[num1].next=head[x]; head[x]=num1++; } stack<int>Q; void Tarjan(int u,int father) { int i,j,v,flag=0; low[u]=dfs[u]=idx++; Q.push(u); for(i=head[u];i!=-1;i=E[i].next) { j=E[i].ed; if(dfs[j]==-1) { Tarjan(j,u); low[u]=low[u]>low[j]?low[j]:low[u]; } else if(j==father) { if(flag) low[u]=low[u]>dfs[j]?dfs[j]:low[u]; flag++; } else low[u]=low[u]>dfs[j]?dfs[j]:low[u]; } if(dfs[u]==low[u]) { do { v=Q.top(); Q.pop(); belong[v]=ans; }while(v!=u); ans++; } } void read() { memset(head,-1,sizeof(head)); num1=0; for(int i=0;i<num;i+=2) { int x=belong[E[i].st]; int y=belong[E[i].ed]; if(x==y)continue; Addedge(x,y); Addedge(y,x); } } int dis; int dist(int u) { ins[u]=1; int max=0,mmax=0; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].ed; if(ins[v]==1)continue; int temp=dist(v); if(temp>mmax) { max=mmax; mmax=temp; } else if(temp>max) { max=temp; } } if(dis<(mmax+max+1)) dis=mmax+max+1; return mmax+1; } int main() { int i,m,x,y; while(scanf("%d%d",&n,&m),n||m) { memset(head,-1,sizeof(head)); num=0; for(i=0;i<m;i++) { scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } memset(dfs,-1,sizeof(dfs)); memset(low,-1,sizeof(low)); memset(ins,0,sizeof(ins)); idx=ans=0; Tarjan(1,-1); read(); memset(ins,0,sizeof(ins)); dis=0; dist(1); printf("%d\n",ans-dis); } return 0; }