题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612
题意:给定一个无向图,问加一条边后最少的桥数是多少。
思路:找出边双连通分量后缩点成一棵树,然后我们要是加一条边使桥数最少,显然是去找树的直径,
所以两边DFS去找树的直径即可,注意这里很坑,重边是不算桥的,所以要特殊处理,下面给出两种实现的代码。
#pragma comment(linker, "/STACK:102400000,102400000") #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #define lson root<<1,l,mid #define rson root<<1|1,mid+1,r #define Key_Value ch[ch[root][1]][0] #define DBN1(a) cerr<<#a<<"="<<(a)<<" " #define DBN2(a,b) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<" " #define DBN3(a,b,c) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<" " #define DBN4(a,b,c,d) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<" " #define DBN5(a,b,c,d,e) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<" " #define DBN6(a,b,c,d,e,f) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<", "<<#f<<"="<<(f)<<" " #define clr(a,x) memset(a,x,sizeof(a)) using namespace std; typedef long long ll; const int maxn=200000+5; const int INF=0x3f3f3f3f; const int P=1000000007; const double PI=acos(-1.0); template<typename T> inline T read(T&x){ x=0;int _f=0;char ch=getchar(); while(ch<'0'||ch>'9')_f|=(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x=_f?-x:x; } struct Edge{ int to; bool iscut; Edge(int _,bool __):to(_),iscut(__){} }; int n,m,u,v,bcc_cnt,s,mx,dfs_clock,bccno[maxn],pre[maxn],low[maxn],dis[maxn]; vector<int>G[maxn]; vector<int>G2[maxn]; vector<Edge>edges; void init(){ bcc_cnt=dfs_clock=0; memset(pre,0,sizeof(pre)); memset(bccno,0,sizeof(bccno)); for (int i=1;i<=n;i++) G[i].clear(),G2[i].clear(); edges.clear(); } int dfs1(int u,int f){ int lowu=pre[u]=++dfs_clock; for (int i=0;i<(int)G[u].size();i++){ int v=edges[G[u][i]].to; if (!pre[v]){ int lowv=dfs1(v,u); lowu=min(lowu,lowv); if (lowv>pre[u]) edges[G[u][i]].iscut=true,edges[G[u][i]^1].iscut=true; } else if (pre[v]<pre[u] && v!=f) lowu=min(lowu,pre[v]); } return low[u]=lowu; } void dfs2(int u){ bccno[u]=bcc_cnt; for (int i=0;i<(int)G[u].size();i++){ Edge &e=edges[G[u][i]];int v=e.to; if (!bccno[v] && !e.iscut) dfs2(v);//天然避开了重边的问题,因为有重边那么重边的iscut肯定是false肯定会被合并到边双连通分量里 } } void find_bcc(){ for (int i=1;i<=n;i++) if (!pre[i]) dfs1(i,-1); for (int i=1;i<=n;i++) if (!bccno[i]) bcc_cnt++,dfs2(i); } void dfs3(int u,int f,int dis){ if (dis>mx){ mx=dis; s=u; } for (int i=0;i<(int)G2[u].size();i++){ int v=G2[u][i]; if (v==f) continue; dfs3(v,u,dis+1); } } int main(){ while (~scanf("%d%d",&n,&m)&&n+m){ init(); for (int i=1;i<=m;i++){ read(u),read(v); edges.push_back(Edge(v,false)); edges.push_back(Edge(u,false)); int m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } find_bcc(); if (bcc_cnt==1){ puts("0"); continue; } for (int u=1;u<=n;u++){ for (int i=0;i<(int)G[u].size();i++){ int v=edges[G[u][i]].to; if (bccno[u]!=bccno[v]){ G2[bccno[u]].push_back(bccno[v]); } } } mx=0; dfs3(1,-1,0); dfs3(s,-1,0); printf("%d ",bcc_cnt-mx-1); } return 0; }
#pragma comment(linker, "/STACK:102400000,102400000") #include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #define lson root<<1,l,mid #define rson root<<1|1,mid+1,r #define Key_Value ch[ch[root][1]][0] #define DBN1(a) cerr<<#a<<"="<<(a)<<" " #define DBN2(a,b) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<" " #define DBN3(a,b,c) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<" " #define DBN4(a,b,c,d) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<" " #define DBN5(a,b,c,d,e) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<" " #define DBN6(a,b,c,d,e,f) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<", "<<#f<<"="<<(f)<<" " #define clr(a,x) memset(a,x,sizeof(a)) using namespace std; typedef long long ll; const int maxn=200000+5; const int INF=0x3f3f3f3f; const int P=1000000007; const double PI=acos(-1.0); template<typename T> inline T read(T&x){ x=0;int _f=0;char ch=getchar(); while(ch<'0'||ch>'9')_f|=(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x=_f?-x:x; } int n,m,u,v,bcc_cnt,s,mx,dfs_clock,bccno[maxn],pre[maxn],low[maxn]; vector<int>G[maxn]; vector<int>G2[maxn]; stack<int>S; void init(){ bcc_cnt=dfs_clock=0; memset(pre,0,sizeof(pre)); for (int i=1;i<=n;i++) G[i].clear(),G2[i].clear(); while (!S.empty())S.pop(); } int dfs1(int u,int f){ int lowu=pre[u]=++dfs_clock,k=0; S.push(u); for (int i=0;i<(int)G[u].size();i++){ int v=G[u][i]; if (v==f && !k){//重边保证可以走 k++; continue; } if (!pre[v]){ int lowv=dfs1(v,u); lowu=min(lowu,lowv); } else if (pre[v]<pre[u]) lowu=min(lowu,pre[v]); } if (lowu==pre[u]){ bcc_cnt++; for (;;){ int v=S.top();S.pop(); bccno[v]=bcc_cnt; if (v==u) break; } } return low[u]=lowu; } void find_bcc(){ for (int i=1;i<=n;i++) if (!pre[i]) dfs1(i,-1); } void dfs2(int u,int f,int dis){ if (dis>mx){ mx=dis; s=u; } for (int i=0;i<(int)G2[u].size();i++){ int v=G2[u][i]; if (v==f) continue; dfs2(v,u,dis+1); } } int main(){ while (~scanf("%d%d",&n,&m)&&n+m){ init(); for (int i=1;i<=m;i++){ read(u),read(v); G[u].push_back(v); G[v].push_back(u); } find_bcc(); if (bcc_cnt==1){ puts("0"); continue; } for (int u=1;u<=n;u++){ for (int i=0;i<(int)G[u].size();i++){ int v=G[u][i]; if (bccno[u]!=bccno[v]){ G2[bccno[u]].push_back(bccno[v]); } } } mx=0; dfs2(1,-1,0); dfs2(s,-1,0); printf("%d ",bcc_cnt-mx-1); } return 0; }