/* 题意:N个点,M条无向有权边,求一个数,使得加任何一条边后,可以破坏一条小于或等于这个数的边,使得不连通 分析:先缩点形成树。而后,加上的边一定会包含最小的边权。所以分别以这条边的两端点建树。记录以某个点为根结点 的最小边权值,然后再搜一遍,确定方向。 */ #include<stdio.h> #include<algorithm> #include<iostream> using namespace std; const __int64 maxn=11000; const __int64 maxm=210000; const __int64 maxint=110000000; struct edge { __int64 u,v,w,next; }e[maxm],e1[maxm]; __int64 edgeNum,top,tnum,num,first[maxn],low[maxn],DFN[maxn],belong[maxn],q[maxn]; __int64 in[maxn],lmin[maxn]; __int64 enum1,first1[maxn],sum,f,f1,f2; bool inq[maxn]; void Addedge(__int64 u,__int64 v,__int64 w,__int64 first[],__int64 &edgeNum,edge e[]) { e[edgeNum].u=u,e[edgeNum].v=v,e[edgeNum].w=w,e[edgeNum].next=first[u],first[u]=edgeNum++; e[edgeNum].u=v,e[edgeNum].v=u,e[edgeNum].w=w,e[edgeNum].next=first[v],first[v]=edgeNum++; } void Tarjan(__int64 t,__int64 f) { low[t]=DFN[t]=++tnum; q[top++]=t; inq[t]=true; __int64 i,k; for(k=first[t];k!=-1;k=e[k].next) { i=e[k].v; if(i==f) continue; if(!DFN[i]) { Tarjan(i,t); if(low[t]>low[i]) low[t]=low[i]; } else if(inq[i]&&low[t]>DFN[i]) low[t]=DFN[i]; } if(low[t]==DFN[t]) { ++num; do { inq[q[--top]]=false; belong[q[top]]=num; }while(q[top]!=t); } } __int64 Min(__int64 a,__int64 b) { return a<b? a:b; } void DFS(__int64 t,__int64 p) { __int64 k,j,jj,ii=-1,kk=maxint; for(k=first1[t];k!=-1;k=e1[k].next) { j=e1[k].v; if(j==f1||j==f2||j==p) continue; DFS(j,t); jj=Min(lmin[j],e1[k].w);//子代或这条边的较小值为最小的边 if(lmin[t]>jj) lmin[t]=jj; if(jj<kk) { kk=jj; ii=j;//记录最小的边的走向 } } for(k=first1[t];k!=-1;k=e1[k].next) { j=e1[k].v; if(j==f1||j==f2||j==p||j==ii) continue;//不是含最小的边的子树 jj=Min(lmin[j],e1[k].w); if(jj<sum) sum=jj; } if(ii!=-1)//走向最小的边的子树 DFS(ii,t); } int main() { __int64 n,m,i,j,k,u,v,w; while(scanf("%I64d%I64d",&n,&m)!=EOF) { memset(first,-1,sizeof(first)); for(edgeNum=0,i=0;i<m;i++) { scanf("%I64d%I64d%I64d",&u,&v,&w); Addedge(u,v,w,first,edgeNum,e); } //Tarjan算法算边连通分量 memset(DFN,0,sizeof(DFN)); memset(inq,false,sizeof(inq)); memset(belong,0,sizeof(belong)); for(top=0,tnum=0,num=0,i=1;i<=n;i++) if(!DFN[i]) Tarjan(i,-1); //根据边连通分量缩点建树,并确定树的根结点 memset(in,0,sizeof(in)); memset(first1,-1,sizeof(first1)); for(enum1=0,j=100000000,k=-1,i=0;i<m;i++) if(belong[e[2*i].u]!=belong[e[2*i].v]) { Addedge(belong[e[2*i].u],belong[e[2*i].v],e[2*i].w,first1,enum1,e1); in[belong[e[2*i].u]]++; in[belong[e[2*i].v]]++; if(e[2*i].w<j) { j=e[2*i].w; k=2*i; } } for(j=0,i=1;i<=num;i++) { if(in[i]==0)//注意数据有可能不连通,不加这条就会TLE break; if(in[i]<=1) j++; } if(i<=num||j<=2)//叶子结点小于或等于2个 { printf("-1\n"); continue; } for(i=1;i<=num;i++)//以i为根结点的子树中最小的边权值 lmin[i]=maxint; f1=belong[e[k].u]; f2=belong[e[k].v]; //分别以f1,f2为根结点,找第二小的路径 sum=maxint; DFS(f1,-1); DFS(f2,-1); if(sum==maxint) printf("-1\n"); else printf("%I64d\n",sum); } return 0; }