tarjan
樹的直徑
HDU4612
給定一個無向連通圖,求增加一條邊後,割邊的最少可能的條數
先用縮點(邊雙連通分量),剩下的就是割邊構成的樹,我們在任意兩點間加邊,就等於在他們所在的邊雙連通分量加邊
於是兩個點在樹上的鏈加上加的邊構成的一個環,就減少了鏈長的割邊
想要割邊最少就是求樹的直徑
樹的直徑可以用新建圖加兩遍
所以:縮點+樹的直徑
注:手動開棧
數據大,深搜會爆棧
int size = 8 << 20; //256兆,size代表棧空間的字節數
char *p = (char*)malloc(size) + size;//開棧空間,esp爲棧頂指針,因而要加size
__asm__("movl %0, %%esp\n" :: "r"(p));//內嵌彙編
記下來吧,緊接函數
#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+4,M=1e6+4;
struct edge{
int u,v,nxt;
}e[M<<1],r[M<<1];
int first[N],cnt=1,cn=0,ct=0;
int n,m,tot=0,idx=0,dfn[N],low[N],vis[N],q[N],top=0,scc[N];
bool cut[M<<1];
inline void add(int u,int v){
e[++cnt].v=v;e[cnt].u=u;
e[cnt].nxt=first[u];first[u]=cnt;
}
inline void add2(int u,int v){
r[++ct].v=v;r[ct].nxt=first[u];first[u]=ct;
}
inline void tarjan(int x,int from){
q[++top]=x;vis[x]=1;
dfn[x]=low[x]=++idx;
for(int i=first[x],v;i;i=e[i].nxt){
v=e[i].v;
if(!dfn[v]){
tarjan(v,i);
low[x]=min(low[x],low[v]);
if(low[v]>dfn[x]){
cut[i]=cut[i^1]=1;
tot++;
}
}
if((i^1)!=from)low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
++cn;
while(1){
int w=q[top--];
vis[w]=0;scc[w]=cn;
if(w==x)break;
}
}
}
int ans=0,mx=0;
inline void dfs(int x,int dep,int fa){
if(dep>mx){mx=dep;ans=x;}
for(int i=first[x],v;i;i=r[i].nxt){
v=r[i].v;
if(v==fa)continue;
dfs(v,dep+1,x);
}
}
int main(){
int size = 8 << 20; //256兆,size代表棧空間的字節數
char *p = (char*)malloc(size) + size;//開棧空間,esp爲棧頂指針,因而要加size
__asm__("movl %0, %%esp\n" :: "r"(p));//內嵌彙編
while(1){
scanf("%d%d",&n,&m);
if(!n&&!m)return 0;
memset(first,0,sizeof(first));
cnt=1;ans=mx=cn=ct=top=tot=idx=0;
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(cut,0,sizeof(cut));
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i,0);
memset(first,0,sizeof(first));
for(int i=2;i<=cnt;i+=2)
if(cut[i]){
add2(scc[e[i].u],scc[e[i].v]);
add2(scc[e[i].v],scc[e[i].u]);
}
dfs(1,0,0);
mx=0;
dfs(ans,0,0);
printf("%d\n",tot-mx);
}
return 0;
}