题意: 有一幅图,现在要加一条边,加边之后要你删除一条边,使图不连通,费用为边的费用,要你求的是删除的边的最小值的最大值(每次都可以删除一条边,选最小的删除,这些最小中的最大就为答案) 首先要进行缩点,把图缩为一棵树,因此,加入一条边后图就会存在一个环,环中的任何一条边删除后都不会导致图不连通 之后找一条最小的边,可以说这条边肯定是在加边之后的连通块里的,因为如果不在连通块里,那就直接可以把这条最小的边删掉,而达不到求出答案的目的 找到边后,分别从边的两点开始遍历,要遍历出一条路径来,并且边上的权值要尽可能的小,因为这样才能让不在环中的边尽可能的大,然后,答案就是每个节点的次小儿子的最小值,如果没有次小儿子就不能算(就是说只有一个儿子,即节点不是三叉的),因为我完全可以把它和最小的边放到一个连通块中,那样答案就应该更大了。 终上所述:先进行无向图的缩点,再在树上找最小的边,最后分别从边的两点出发,遍历树,找节点的次小儿子节点中的最小值 举个简单的例子(括号内的数字代表边上的权值)1和8间的权值为1,是最小的 1---8 / \(3) (2)/ \ 2 3 (4) / \(5) (6)/ \(7) / \ / \ 4 5 6 7 左子树中2的子节点有次小值5,右子树中3的子节点次小值为7,两个次小值间的最小值是5,即答案 现在,比如所你要把3、4连起来。我可以去掉2、5之间的边让图不连通,花费为5 把3、5连起来,我自然可以删掉2、4,花费为4, 一个节点的次小值和最小值(比如说4、5两点)不可能被同时连进一个连通块(或环)中(因为必须把最小的那条边加进环中),正是利用这个性质,不管把那两个点连起来,我们都可以找到一个最小值或次小值来删掉使图不连通,注意:再重复一遍,同一个节点的最小值和次小值不会被加进同一个环,因此,这些次小值中的最小的那条边的权值就是答案。(这时你如果把次小的边加进环中,如2--5,自然可以删掉一条更小的边 如2--4 使图不连通,相反,如果没有把次小的边加进去,那次小的就是答案) #include<stdio.h> #include<string.h> #include<vector> #include<algorithm> #include<iostream> using namespace std; const int maxn = 10010; int tot,n,m,ans; const int inf = 999999999; struct Edge { int t,w; int next; int vis; }edge[1000005]; int head[maxn],E; void add(int s,int t,int w) { edge[E].t=t; edge[E].w=w; edge[E].vis=0; edge[E].next=head[s]; head[s]=E++; } int Btype,Time,N,M; int dfn[maxn],low[maxn],belong[maxn]; int st[maxn],Top; int tt[100010][3],cnt; inline int min(int a,int b){return a<b?a:b;} void tarjan(int s)//无向图求环 { int i,t; st[++Top]=s; dfn[s]=low[s]=++Time; for (i=head[s];i!=-1;i=edge[i].next) { if(edge[i].vis)continue; edge[i].vis=edge[i^1].vis=1; t=edge[i].t; if (!dfn[t]) { tarjan(t); low[s]=min(low[s],low[t]); if(dfn[s]<low[t])//桥,也是生成树的边。 { tt[++cnt][0]=s,tt[cnt][1]=t,tt[cnt][2]=edge[i].w; } } else low[s]=min(low[s],dfn[t]); } if(dfn[s]==low[s])//有环 { Btype++; do{ t=st[Top--]; belong[t]=Btype; }while(t!=s); } } void SCC(int n) { int i; Time=0;Btype=0;Top=0; memset(dfn,0,sizeof(int)*(n+1)); for(i=1;i<=n;i++)if(!dfn[i]) tarjan(i); } int find(int s,int t) { int i; int Min=inf,vice_Min=inf,rr=inf; for(i=head[s];i!=-1;i=edge[i].next) { int v=edge[i].t; if(v==t) continue; int w=find(v,s);//printf("w=%d\n",w); if(w<vice_Min) vice_Min=w; if(edge[i].w<vice_Min) vice_Min=edge[i].w; if(Min>vice_Min) swap(vice_Min,Min); if(Min<rr) rr=Min; } if(ans>vice_Min) ans=vice_Min; return rr; } int a1,a2,flag; int main() { int i,a,b,w; while(scanf("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head));E=0; for(i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&w); add(a,b,w); add(b,a,w); } cnt=0; SCC(n); memset(head,-1,sizeof(head)); E=0; int C=inf; for(i=1;i<=cnt;i++) { add(belong[tt[i][0]],belong[tt[i][1]],tt[i][2]); add(belong[tt[i][1]],belong[tt[i][0]],tt[i][2]); if(tt[i][2]<C){C=tt[i][2]; a=belong[tt[i][0]],b=belong[tt[i][1]];} } ans=inf; find(a,b); find(b,a); if(ans==inf) printf("-1\n"); else printf("%d\n",ans); } return 0; }