hdu4612 Warm up[边双连通分量缩点+树的直径]
给你一个连通图,你可以任意加一条边,最小化桥的数目。
添加一条边,发现在边双内是不会减少桥的。只有在边双与边双之间加边才有效。于是,跑一遍边双并缩点,然后就变成一棵树,这样要加一条非树边,路径上的点(边双)就都变成一个大边双了,所以问题转化为求树上最长路径,跑直径即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define mst(x) memset(x,0,sizeof x) 8 #define dbg(x) cerr << #x << " = " << x <<endl 9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl 10 using namespace std; 11 typedef long long ll; 12 typedef double db; 13 typedef pair<int,int> pii; 14 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 15 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 19 template<typename T>inline T read(T&x){ 20 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 21 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 22 } 23 const int N=2e5+7,M=1e6+7; 24 struct thxorz{int to,nxt;}G1[M<<1],G2[N<<1]; 25 int Head1[N],Head2[N],tot1,tot2; 26 int n,m; 27 inline void Addedge(int x,int y){ 28 G1[++tot1].to=y,G1[tot1].nxt=Head1[x],Head1[x]=tot1; 29 G1[++tot1].to=x,G1[tot1].nxt=Head1[y],Head1[y]=tot1; 30 } 31 inline void Addtedge(int x,int y){ 32 G2[++tot2].to=y,G2[tot2].nxt=Head2[x],Head2[x]=tot2; 33 G2[++tot2].to=x,G2[tot2].nxt=Head2[y],Head2[y]=tot2; 34 } 35 #define y G1[j].to 36 int dfn[N],low[N],cut[M<<1],cnt; 37 void tarjan(int x,int i){ 38 dfn[x]=low[x]=++cnt; 39 for(register int j=Head1[x];j;j=G1[j].nxt)if(j^(i^1)){ 40 if(!dfn[y]){ 41 tarjan(y,j);MIN(low[x],low[y]); 42 if(low[y]>dfn[x])cut[j]=cut[j^1]=1; 43 } 44 else MIN(low[x],dfn[y]); 45 } 46 } 47 int bel[N],dcc; 48 void dfs(int x){ 49 bel[x]=dcc; 50 for(register int j=Head1[x];j;j=G1[j].nxt)if(!bel[y]&&!cut[j])dfs(y); 51 } 52 #undef y 53 #define y G2[j].to 54 int dep,pt; 55 void tree_dfs(int x,int fa,int d){ 56 if(MAX(dep,d))pt=x; 57 for(register int j=Head2[x];j;j=G2[j].nxt)if(y^fa)tree_dfs(y,x,d+1); 58 } 59 #undef y 60 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 61 while(read(n),read(m),n||m){ 62 tot1=1;dcc=tot2=cnt=dcc=0;mst(Head1),mst(Head2),mst(dfn),mst(low),mst(cut),mst(bel); 63 for(register int i=1,x,y;i<=m;++i)read(x),read(y),Addedge(x,y); 64 for(register int i=1;i<=n;++i)if(!dfn[i])tarjan(i,0); 65 for(register int i=1;i<=n;++i)if(!bel[i])++dcc,dfs(i); 66 for(register int t=2,u,v;t<=tot1;t+=2){ 67 u=G1[t].to,v=G1[t^1].to; 68 if(bel[u]^bel[v])Addtedge(bel[u],bel[v]);//dbg2(bel[u],bel[v]); 69 } 70 dep=0,tree_dfs(1,0,1);dep=0,tree_dfs(pt,0,1); 71 printf("%d\n",dcc-dep); 72 } 73 return 0; 74 }
总结:和桥有关的可以首先考虑缩点建树,因为树有很好的性质,并且树边都是有桥连接起来的,同一个边双方便处理。