HDU 4612 Warm up
给出一个无向图,你可以加一条边,使得加上边之后的图割边数量最少。
方法:每个边双连通分量缩点,形成一个树,树上的每条边都是割边,割边数量为S1;
接下来只要算出树上最长路径(树的直径)就可以了,最长路径两段连线,路径上的割边都不可能再成为割边了,记最长路径长度为S2;
Ans=S1-S2;
第一步可以用Tarjan算法
树的直径可以这样求:先随便找一个点P,DFS一下,找到与P距离最远的那个点St;然后从St出发,再进行一次DFS,与St相距最远的那个点的距离就是树的直径。
这个题目搞了一天,一直是MLE,后来把vector改成数组就AC了.....
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn=200000+10; const int Maxn=2*1000000+10; const int INF=0x7FFFFFFF; int low[maxn]; int dfn[maxn]; int U[Maxn],V[Maxn]; int flag[Maxn]; int head[maxn]; struct Edge { int to,ans; int next; } edge[Maxn]; int N,M; int tmpdfn; int tot; int son; int Start,End; int TxT[maxn]; int ShuYu[maxn]; int SS,Ans,JiLu,MA,St; vector<int>Tree[maxn]; int Biao[maxn]; void init() { for(int i=0; i<=N; i++) Tree[i].clear(); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(flag,0,sizeof(flag)); memset(TxT,0,sizeof(TxT)); memset(ShuYu,0,sizeof ShuYu); memset(Biao,0,sizeof Biao); memset(head,-1,sizeof head); low[1]=dfn[1]=1; tmpdfn=0; tot=0; son=0; SS=0; } void AddEdge(int u,int v) { edge[tot].to=v; edge[tot].next=head[u]; edge[tot].ans=0; head[u]=tot++; edge[tot].to=u; edge[tot].next=head[v]; edge[tot].ans=0; head[v]=tot++; } int Tarjan(int u,int id) { tmpdfn++; int lowu=dfn[u]=tmpdfn; for(int i = head[u]; i != -1; i = edge[i].next) { int B=i; if(!dfn[edge[B].to]) { int lowv=Tarjan(edge[B].to,B); lowu=min(lowu,lowv); if(lowv>=dfn[u]) { if(u==1) son++; if(lowv>dfn[u]) { edge[B].ans=1; edge[B^1].ans=1; } } } else if(dfn[edge[B].to]) { if(B/2==id/2) continue; lowu=min(lowu,dfn[edge[B].to]); } } low[u]=lowu; return lowu; } void Dfs(int x,int y) { int XZ=0; for(int i = head[x]; i != -1; i = edge[i].next) { int B=i; if(!flag[B/2]&&!TxT[edge[B].to]) { XZ=1; flag[B/2]=1; TxT[edge[B].to]=1; ShuYu[x]=SS; ShuYu[edge[B].to]=SS; Dfs(edge[B].to,y+1); } } if(!XZ&&!y) ShuYu[x]=SS; } void Slove() { for(int i=0; i<2*M; i++) if(edge[i].ans) flag[i/2]=1; for(int i=Start; i<=End; i++) { if(!TxT[i]) { TxT[i]=1; SS++; Dfs(i,0); } } } void dfs1(int now,int len) { if(len>MA) { MA=len; St=now; } Biao[now]=1; for(int i=0; i<Tree[now].size(); i++) if(Biao[Tree[now][i]]==0) dfs1(Tree[now][i],len+1); } void dfs2(int now,int len) { if(len>MA) MA=len; Biao[now]=1; for(int i=0; i<Tree[now].size(); i++) if(Biao[Tree[now][i]]==0) dfs2(Tree[now][i],len+1); } int main() { while(~scanf("%d%d",&N,&M)) { if(N==0&&M==0) break; init(); for(int i=0; i<M; i++) { scanf("%d%d",&U[i],&V[i]); AddEdge(U[i],V[i]); } Start=1; End=N; Tarjan(1,-1); Slove(); for(int i=0; i<M; i++) { if(ShuYu[U[i]]==ShuYu[V[i]]) continue; Tree[ShuYu[U[i]]].push_back(ShuYu[V[i]]); Tree[ShuYu[V[i]]].push_back(ShuYu[U[i]]); } MA=-INF; dfs1(1,0); memset(Biao,0,sizeof Biao); MA=-INF; dfs2(St,0); Ans=MA; printf("%d\n",SS-1-Ans); } return 0; }