hdu 4612
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4612
题目大意:给你一幅图,问你加一条边,使桥数最小,输出这个最小桥数。
思路:先缩点,那么它就是一棵树,原图的桥数也就是求出来强连通分量的个数-1,再求出树的最长边(点数最多),那么最小的桥数 = 原图的桥数 - 最长边对应的点数。
其实这道题我们比赛的思路已经非常正确了,就是按照上面那么想到的,就是 tarjan()之前只用它做过有向图的缩点,没做过无向图的,当时也一样标记搜过的点去了,一直WA,其实标记搜过的边就好了,还是基本功不够啊。。 = =
另外,原来杭电 STACK_OVERFLOW 了,还能手动增加栈的深度的,这个倒是第一次见。 = =
代码如下:
#pragma comment(linker, "/STACK:10240000000000,10240000000000") #include<cstdio> #include<cstring> #include<stack> #include<vector> #include<algorithm> using namespace std; const int MAX_M = 1000111 ; const int MAX_N = 200111 ; struct Edge { int t,next; } edge[MAX_M<<1]; int tot,head[MAX_N]; void add_edge(int s,int t) { edge[tot].t = t; edge[tot].next = head[s]; head[s] = tot++; } stack <int> s; int dfs_clock,pre[MAX_N],scc_cnt,low_link[MAX_N],sccno[MAX_N]; int vis[MAX_M<<1]; stack <int> ed; void dfs(int u) { low_link[u]=pre[u]=++dfs_clock; s.push(u); for(int i = head[u];i!=-1;i=edge[i].next) { if(vis[i]) continue; int tmp = (i/2)*2 ; vis[tmp] = 1;vis[tmp+1] = 1; ed.push(tmp); int v=edge[i].t; if(!pre[v]) { dfs(v); low_link[u]=min(low_link[u],low_link[v]); } else if(!sccno[v]) low_link[u]=min(low_link[u],pre[v]); } if(pre[u]==low_link[u]) { scc_cnt++; while(!s.empty()) { int x=s.top(); s.pop(); sccno[x]=scc_cnt; if(x==u) break; } } } int n,m; void tarjan() { scc_cnt=0; dfs_clock=0; memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); for(int i=1;i<=n;i++) if(!sccno[i]) { while(!ed.empty()) { int x = ed.top(); vis[x]=vis[x+1]=0; ed.pop(); } dfs(i); } } vector <int> G[MAX_N]; void build() { for(int i = 1;i<=scc_cnt;i++) G[i].clear(); for(int i = 1;i<=n;i++) { for(int e = head[i] ; e!=-1;e = edge[e].next) { int v = edge[e].t; if(sccno[i]!=sccno[v]) { //printf("%d,%d||%d,%d\n",i,sccno[i],v,sccno[v]); G[sccno[i]].push_back(sccno[v]); } } } } int num[MAX_N],maxx; void find(int u,int fa) { int m1 =0,m2 = 0; num[u]=1; for(int i = 0 ; i<G[u].size() ; i++) { int v = G[u][i]; if(v==fa) continue; find(v,u); if(num[v]>m1) { m2 = m1; m1 = num[v]; } else if(num[v]>m2) { m2 = num[v]; } } num[u] = m1+1; maxx = max(maxx,m1+m2); } int main() { while(scanf("%d%d",&n,&m),n+m) { int a,b; tot=0; memset(head,-1,sizeof(head)); for(int i =0;i<m;i++) { scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); } memset(vis,0,sizeof(vis)); tarjan(); /*for(int i = 1;i<=n;i++) printf("i = %d,sccno = %d\n",i,sccno[i]);*/ int pre_bridge = scc_cnt-1; build(); maxx = 0; find(1,-1); //printf("maxx = %d\n",maxx); int ans = pre_bridge - maxx; printf("%d\n",ans); } return 0; }