• HDU


    HDU - 3586  Information Disturbing

      题目大意:从敌人司令部(1号节点)到前线(叶子节点)的通信路径是一个树形结构,切断每条边的联系都需要花费w权值,现在需要你切断前线和司令部的连接,(就是所有叶子节点都到不了根节点),并且总花费不能超过m。问能够实行的方案中,最大花费的最小值,否则输出-1.

      树形dp的题还是很好意识到用树形dp的,但最好是画一画图进行理解和推导,就像现在我随手画的图(第一次发现可以传图片)。

    (画得有点小丑,问题不大)

      现在回到问题,就是我们需要切断1和4,5,6节点联系,那我们有几种选择呢,首先现在6节点,6节点只和3节点相连,3节点和1节点相连,那我们可以通过切断1和3的联系,或者是切断3和6的联系,来实现切断1和6的连接,很明显我们会选择3和6的联系,因为它们的权值较小。推理到左边,要切断1和4,5的联系就有,一.切断1和2的联系,二。切断2和3以及切断2和5的联系这两种,很明显我们会选择切断1和3的联系。我们可以发现如果我们把每个节点视为根节点的话,要切断它和叶子节点的关系无非有两种联系,切断它和它下一级的节点的联系,或者它下一级的节点切断和它所有节点的联系。我们用dp[i]来表示i节点切断它和它所有叶子节点的总花费最小值就有

    (字也丑。。。)

      但现在问题是要找到的是一个最大花费的最小值,如果我们直接树形dp跑一遍的话就只能找到一个方案,并且其中的最大值不一定就是最小的,所以我们需要二分一个答案,然后用这个答案作为一个限制去跑树形dp看该方案可不可行?那么怎么实现这个限制呢?我想到的是如果一条边的权值已经大于限制值了,那就让它等于m+1,这样的话如果没有其他能代替它的更小的边,最终总花费肯定是大于m的,也就是方案不可行。其他细节详情见代码如下

      

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=1108;
     6 struct Side{
     7     int v,ne,w;
     8 }S[2*N];
     9 int sn,n,m,head[N],dp[N];
    10 void add(int u,int v,int c)
    11 {
    12     S[sn].v=v;
    13     S[sn].w=c;
    14     S[sn].ne=head[u];
    15     head[u]=sn++;
    16 }
    17 int dfs(int u,int f,int lim)
    18 {
    19     dp[u]=0;
    20     for(int i=head[u];i!=-1;i=S[i].ne)
    21     {
    22         int v=S[i].v;
    23         if(v!=f)
    24         {
    25             dfs(v,u,lim);
    26             int cost=(S[i].w>lim ? m+1 : S[i].w);//如果权值超过限制,设为m+1 
    27             dp[u]+=min(dp[v],cost);//子节点的花费以及相连的边权值中取个最小值 
    28             //当前节点加上所有子节点需要切断和叶子节点的花费 
    29         }
    30     }
    31     if(dp[u]==0)//这个是用来判断它是不是叶子节点的
    32         dp[u]=0x3f3f3f3f;//叶子节点的dp设个最大值,它的父节点只能切断和它相连的边 
    33     return dp[u]; 
    34 }
    35 int main()
    36 {
    37     int a,b,w;
    38     while(scanf("%d%d",&n,&m)&&(n||m))
    39     {
    40         for(int i=0;i<=n;i++)
    41             head[i]=-1;
    42         int l=1001,r=0;//l所有边中的最小值,r所有边中的最大值 
    43         sn=0;
    44         for(int i=1;i<n;i++)
    45         {
    46             scanf("%d%d%d",&a,&b,&w);
    47             add(a,b,w);
    48             add(b,a,w);
    49             l=min(l,w);
    50             r=max(r,w);
    51         }
    52         int ans=-1;
    53         while(l<=r)
    54         {
    55             int mid=(l+r)>>1;
    56             if(dfs(1,0,mid)<=m)//判断这个答案是否可行 
    57                 ans=mid,r=mid-1;//可行的话,继续调小 
    58             else
    59                 l=mid+1;
    60         }
    61         printf("%d
    ",ans);
    62     }
    63     return 0;
    64 }
    太君这边请~
  • 相关阅读:
    [POJ 2096] Collecting Bugs
    [POJ 3774] Scout YYF I
    [HDU 4418] Time travel
    [hdu 4586] Play the Dice
    [HDU 4507] 吉哥系列故事――恨7不成妻
    [HDU 4734] F(x)
    [Codeforces] Round #352 (Div. 2)
    刷题向》关于一道像差分约束的数学题BZOJ1045(NORMAL)
    刷题向》关于一道奇怪的贪心(田忌赛马)BZOJ1034(NORMAL-)
    刷题向》关于线段树的区间开根号 BZOJ3211(NORMAL+)
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10534540.html
Copyright © 2020-2023  润新知