【無向Tarjan+樹的直徑】HDU
阿新 • • 發佈:2018-12-09
題意:
給出一張無向圖,加一條邊,問能使得圖中橋的數量最少是多少。
題解:
無向圖Tarjan縮點,形成一棵樹。樹上的最長鏈加一條邊是最優解。答案就是原本橋的數量減去樹的直徑。
#include<iostream> #include<cstdio> #include<string.h> #include<string> #include<algorithm> #include<stack> #include<queue> using namespace std; const int M=2e6+7; const int N=2e5+7; int n,m,ans; struct Edge{ int v,nxt; Edge(int v=0,int nxt=0):v(v),nxt(nxt){} }edge[M],e[M]; int p[N],edn; void add(int u,int v){ edge[++edn]=Edge(v,p[u]);p[u]=edn; edge[++edn]=Edge(u,p[v]);p[v]=edn; } int dfn[N],low[N],bcc[N],bccnum,index,st[N],top; bool ef[M]; void tarjan(int u){ dfn[u]=low[u]=++index; st[++top]=u; for(int i=p[u];~i;i=edge[i].nxt){ int v=edge[i].v; if(ef[i]) continue; ef[i]=ef[i^1]=1; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); /*if(dfn[u]<low[v]){ ef[i]=ef[i^1]=2; }*/ } else low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ bccnum++; while(1){ int x=st[top--]; bcc[x]=bccnum; if(x==u) break; } } } int hd[N],ed; void ad(int u,int v){ e[++ed]=Edge(v,hd[u]);hd[u]=ed; //e[++ed]=Edge(u,hd[v]);hd[v]=ed; } void rebuild(){ memset(hd,-1,sizeof(hd));ed=-1; for(int x=1;x<=n;x++){ int u=bcc[x]; for(int i=p[x];~i;i=edge[i].nxt){ int v=bcc[edge[i].v]; if(u==v) continue; ad(u,v); } } } void init(){ memset(bcc,0,sizeof(bcc));bccnum=0; memset(p,-1,sizeof(p));edn=-1; memset(dfn,0,sizeof(dfn)); memset(ef,false,sizeof(ef)); top=index=ans=0; } typedef struct Node{ int id,stp; Node(int id=0,int stp=0):id(id),stp(stp){} }; bool vis[N]; Node bfs(int x){ memset(vis,0,sizeof(vis)); queue<Node>q; q.push(Node(x,0));vis[x]=true; Node t; while(!q.empty()){ t=q.front();q.pop(); int u=t.id; for(int i=hd[u];~i;i=e[i].nxt){ int v=e[i].v; if(vis[v]) continue; vis[v]=true; q.push(Node(v,t.stp+1)); } } return t; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0) break; init(); int u,v; for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); add(u,v); } int ans=0; for(int i=1;i<=n;i++){ if(!bcc[i]) tarjan(i); } rebuild(); Node x=bfs(1); Node y=bfs(x.id); printf("%d\n",bccnum-1-y.stp); } }