大连赛区网赛1005 对方加一条边,我方减一条边最少的费用
2011-09-03 17:15
330 查看
/* 题意: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; }
相关文章推荐
- hdu4003 2011大连赛区网赛1003一棵树,K个机器人遍历所有结点所需的最少权值和
- 【2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛】 J Our Journey of Dalian Ends 【拆点费用流】
- 动态规划 杭电4001 大连赛区网络赛水题
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 I.Minimum(线段树_单点修改,查询区间最大最少值)
- 【2016-大连赛区网络赛-F】水题(Football Games,hdu 5873)
- 2017 乌鲁木齐赛区网络赛Our Journey of Dalian Ends (费用流+拆点建图)
- hdu 5875 Function -线段树+取余 -ICPC网络赛大连赛区
- ACM-ICPC国际大学生程序设计竞赛亚洲区大连赛区(2016)地区赛——花开花落终有时
- 2016 ICPC大连赛区 hdu5974 Convex
- hdu 4001 dp 2011大连赛区网络赛A
- NYOJ 1023 还是回文(DP,花最少费用形成回文串)
- GDUT Problem E: 逃票的chanming(2) SPFA (维护逃票次数最少基础上维护最小费用)
- 大连赛区网络赛部分题目解题报告
- 杭电 4007 亚洲区域赛大连赛区
- 动态规划 杭电4001 大连赛区网络赛水题
- uva1629 切方格使得每个方格中只有一个物品,求最少切割费用 记忆化搜索
- hdu 5869 Different GCD Subarray Query 2016ACM/ICPC大连赛区网络赛1002
- HDU 4282 A very hard mathematic problem 第37届ACM/ICPC长春赛区网络赛1005题 (暴力)
- CCPC杭州赛区和ICPC大连赛区
- 2016 ICPC大连赛区 hdu5976 Detachment