hdu 4005

53 篇文章 0 订阅


题意:

有一幅图,现在要加一条边,加边之后要你删除一条边,使图不连通,费用为边的费用,要你求的是删除的边的最小值的最大值(每次都可以删除一条边,选最小的删除,这些最小中的最大就为答案)

首先要进行缩点,把图缩为一棵树,因此,加入一条边后图就会存在一个环,环中的任何一条边删除后都不会导致图不连通

之后找一条最小的边,可以说这条边肯定是在加边之后的连通块里的,因为如果不在连通块里,那就直接可以把这条最小的边删掉,而达不到求出答案的目的

找到边后,分别从边的两点开始遍历,要遍历出一条路径来,并且边上的权值要尽可能的小,因为这样才能让不在环中的边尽可能的大,然后,答案就是每个节点的次小儿子的最小值,如果没有次小儿子就不能算(就是说只有一个儿子,即节点不是三叉的),因为我完全可以把它和最小的边放到一个连通块中,那样答案就应该更大了。

终上所述:先进行无向图的缩点,再在树上找最小的边,最后分别从边的两点出发,遍历树,找节点的次小儿子节点中的最小值

举个简单的例子(括号内的数字代表边上的权值)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;
 }


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值