zoukankan      html  css  js  c++  java
  • 【UVA12093】Protecting Zonk (树形DP)

    题意:

      给定一个有n个节点的无根树,有两种装置A和B,每种都有无限多个。在某个节点X使用A装置需要C1的花费,并且此时与节点X相连的边都被覆盖。在某个节点X使用B装置需要C2的花费,并且此时与节点X相连的边以及与X相连的点相连的边都被覆盖。求覆盖所有边的最小花费。

    分析:

      首先无根树可以先dfs确定根。考虑选择装置A和装置B的影响。

      装置A只会影响节点u连出去的边。而装置B还会影响u相连的点相连的边,也就是说与节点u距离为2的边也会被影响。

      也就是说,对于边(u,fa[u]),如果fa[fa[u]]装上装置B,那么这条边就被覆盖。但只有这种情况吗?有一个容易漏的情况就是如果u、v的父亲都是fa[u],如果在v上装了装置B,那么边(u,fa[u])就被覆盖了。(像我这种想东西不全面的人就容易把这种情况漏掉,导致我后来整个代码重打了一遍~~)

      而对于装置A,处理过程就相对简单了,下面我只说说我怎么处理装置B的。

      用了个四维DP,dp[x][a][b][c](a=0~2; b=0~2; c=0~1)表示节点x,选了a装置(0表示不选,1表示装置A,2表示装置B),fa[x]选了b装置,目前边(u,fa[u])的状态为c。

      如果c=0,那么u的子节点中一定要有至少一个装上装置B。而对于上述说的装置B的第二种情况,我们也可以用这个一起计算。

      那么就是两种方案:

      1、u的子节点中至少有一个装上装置B。

      2、u的子节点中没有装上装置B的。

      当符合条件时,取两者的min值即可。

    代码如下:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 10010
     8 #define INF 100000010
     9 
    10 int dp[Maxn][3][3][2];
    11 int first[Maxn],fa[Maxn];
    12 int n,c1,c2;
    13 
    14 struct node
    15 {
    16     int x,y,next;
    17 }t[2*Maxn];int len;
    18 
    19 void ins(int x,int y)
    20 {
    21     t[++len].x=x;t[len].y=y;
    22     t[len].next=first[x];first[x]=len;
    23 }
    24 
    25 int mymin(int x,int y) {return x<y?x:y;}
    26 
    27 void dfs(int x,int f)
    28 {
    29     fa[x]=f;
    30     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
    31     {
    32         int y=t[i].y;
    33         dfs(y,x);
    34     }
    35 }
    36 
    37 int ffind(int x,int a,int b,int c)// a->x b->fa c->(x,fa[x])
    38 {
    39     if(dp[x][a][b][c]<INF) return dp[x][a][b][c];
    40     int ans=dp[x][a][b][c];
    41     int p=(a!=0||b==2)?1:0,h=0,y,now;
    42     for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])//sons have at least one B
    43     {
    44         y=t[i].y;
    45         now=mymin(mymin(ffind(y,0,a,1),ffind(y,1,a,1)),ffind(y,2,a,1));
    46         h+=now;
    47     }
    48     for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])
    49     {
    50         y=t[i].y;
    51         now=mymin(mymin(ffind(y,0,a,1),ffind(y,1,a,1)),ffind(y,2,a,1));
    52         ans=mymin(ans,h-now+ffind(y,2,a,1));
    53     }
    54     if(c!=0) //sons have no B
    55     {
    56         now=0;
    57         for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])
    58         {
    59             y=t[i].y;
    60             now+=mymin(ffind(y,0,a,p),ffind(y,1,a,1));
    61         }
    62         ans=mymin(ans,now);
    63     }
    64     if(a==1) ans+=c1;
    65     else if(a==2) ans+=c2;
    66     dp[x][a][b][c]=ans;
    67     return ans;
    68 }
    69 
    70 int main()
    71 {
    72     while(1)
    73     {
    74         scanf("%d%d%d",&n,&c1,&c2);
    75         if(n==0&&c1==0&&c2==0) break;
    76         len=0;
    77         memset(first,0,sizeof(first));
    78         for(int i=1;i<n;i++)
    79         {
    80             int x,y;
    81             scanf("%d%d",&x,&y);
    82             ins(x,y);ins(y,x);
    83         }
    84         memset(dp,63,sizeof(dp));
    85         dfs(1,0);
    86         int ans=INF;
    87         ans=mymin(ans,ffind(1,0,0,1));
    88         ans=mymin(ans,ffind(1,1,0,1));
    89         ans=mymin(ans,ffind(1,2,0,1));
    90         printf("%d
    ",ans);
    91     }
    92     return 0;
    93 }
    UVA12093

    2016-03-10 17:16:10

  • 相关阅读:
    [转]web串口调试助手,浏览器控制串口设备
    [转]WEB页获取串口数据
    [转]js串口通信 调用MSCOMM32控件 链接电子秤
    [转]C# serialPort 串口接收中this.Invoke的使用
    [转]C#串口通信 SerialPort类
    [转]How to display the data read in DataReceived event handler of serialport
    [转]c# System.IO.Ports SerialPort Class
    [转]用C#在windows上操控电脑自带蓝牙(入道指南)
    Springboot Actuator之四:重写与注册服务中心的健康检查逻辑(判断依据是tcp连接是否正常)
    二维码支付原理分析及安全性的探究
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5262668.html
Copyright © 2011-2022 走看看