zoukankan      html  css  js  c++  java
  • HDU 4340 Capturing a country

    想了好久才看懂大牛的结题报告,附上链接:http://blog.csdn.net/cyberzhg/article/details/7840922

    自己理解,整理下:刚开始的时候陷入了一个误区,枚举所有点把他们当树根,然后递推:dp[rt][0]+=min(dp[son][0]-ca,dp[son][1]);很明显这个递推是每次全部取固定为子树根了,情况不完全;也就是二维不能完全表示状态;

    dp[N][2][2]

    dp[rt][0][0]:表示以rt为树根的子树根节点选择了A,但是与根节点A联通的块内(即各个子树的根也选了A,由根节点也选A,连通起来的连通块)没有一个是完全花费的(没有确定起点);

    dp[rt][0][0]=sum( min( dp[son][0][0],dp[son][1][1] )  )+A[rt]/2;这个很容易理解,每一棵子树只能由两个选择;

    如果选了dp[son][0][1],那么dp[rt][0][0]是不符合逻辑的跟定义违背,dp[son][1][0]也是错误的;

    dp[rt][0][1]=sum(同上)+min( A[rt], A[rt]/2+EA );

    EA=min( dp[son][0][1]-min(dp[son][0][0],dp[son][1][1]) );蓝色min是针对rt的各个子树的;  dp[rt][0][1]因为要在联通块内找一个A入口,那么入口肯定在根节点或者在子树内,如果在根节点那么只要sum()+A[rt]就可以了,因为入口在跟结点所以在子树中就不需要入口,多入口只会增加费用。

    如果在子树内,那么根节点就不需要,但其中一棵子树就要有一个A入口,所以其中一棵子树要选dp[soni][0][1],所以只要找出最小的就可以了;

    EA :假设子树i被选为有入口的子树,那么dp[rt][0][1]=sum()-min( dp[soni][0][0],dp[soni][1][1] )+dp[soni][0][1]  +A[rt]/2;

    代码如下:

    View Code
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<vector>
     7 using namespace std;
     8 const int N=110;
     9 vector<int > g[N];
    10 int A[N],B[N];
    11 int n;
    12 int dp[N][2][2];//dp[i][0][0]表示以i为根结点的子树i选A,
    13 //且其中关于A的连通中全部去半值;
    14 int dmin(int a,int b){
    15     if (a==-1) return b;
    16     if (a<b) return a;return b;
    17 }
    18 void TREEDP(int rt,int fa){
    19 
    20     int SA=0,SB=0,EA=-1,EB=-1;
    21     int flag=0;
    22     for (int i=0;i<g[rt].size();i++){
    23         int c=g[rt][i];
    24         if (c==fa) continue;
    25         flag=1;
    26         TREEDP(c,rt);
    27         SA+=min(dp[c][0][0],dp[c][1][1]);
    28         SB+=min(dp[c][1][0],dp[c][0][1]);
    29         EA=dmin(EA,dp[c][0][1]-min(dp[c][0][0],dp[c][1][1]));
    30         EB=dmin(EB,dp[c][1][1]-min(dp[c][1][0],dp[c][0][1]));
    31     }
    32     if (flag==0){
    33         dp[rt][0][0]=A[rt]/2;dp[rt][0][1]=A[rt];
    34         dp[rt][1][0]=B[rt]/2;dp[rt][1][1]=B[rt];
    35         return;
    36     }
    37     dp[rt][0][0]=SA+A[rt]/2;
    38     dp[rt][1][0]=SB+B[rt]/2;
    39     dp[rt][0][1]=min(SA+A[rt],SA+A[rt]/2+EA);
    40     dp[rt][1][1]=min(SB+B[rt],SB+B[rt]/2+EB);
    41 
    42 }
    43 int main(){
    44     while (~scanf("%d",&n)){
    45         for (int i=0;i<n;i++) scanf("%d",&A[i+1]);
    46         for (int j=0;j<n;j++) scanf("%d",&B[j+1]);
    47         for (int i=0;i<=n;i++) g[i].clear();
    48         for (int i=0;i<n-1;i++){
    49             int u,v;scanf("%d%d",&u,&v);
    50             g[u].push_back(v);
    51             g[v].push_back(u);
    52         }
    53         int ans;
    54         TREEDP(n-1,0);//任选一个作为根;
    55         ans=min(dp[n-1][0][1],dp[n-1][1][1]);
    56 
    57         printf("%d\n",ans);
    58 
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    【LeetCode-栈】栈排序
    【LeetCode-数组】旋转数组
    【LeetCode-数组】两个数组的交集 II
    【LeetCode-树】二叉树的层次遍历 II
    【LeetCode-字符串】Fizz Buzz
    【LeetCode-数组】数组的相对排序
    解决Oracle表中数据乱码的问题
    docker搭建mysql 用户名密码忘记了怎么办
    java中如何将string 转化成long
    http三次握手四次挥手
  • 原文地址:https://www.cnblogs.com/Rlemon/p/2871905.html
Copyright © 2011-2022 走看看