• [CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities


    题目大意:
      有一棵n个结点的树,请你搞一些破坏。
      直接暴力破坏一个结点i的代价为p[i]。
      当然还有非暴力破坏的方法。
      每个结点i有一个防御上限c[i],如果与这个点直接相连的点中已经有c[i]个被破坏,那么这个点就会自己坏掉。
      一个点坏掉以后要过一秒钟才会带坏周围的点。
      如果不考虑时间问题,如何用最小的代价把整棵树搞坏?

    思路:
      树形DP。
      然而这题并没有明显的上下级关系,也就是说父结点和子结点会互相影响。
      考虑同时做两个DP,f和g。
      f[i]表示先搞坏i子树再搞坏母树的最小代价。
      g[i]表示先搞坏母树再搞坏i子树的最小代价。
      显然对于一个点,不仅有f和g的情况,还分为手动破坏和自动破坏两种情况。
      我们不妨先考虑手动搞坏i点的情况,也就是说,令f[i]=g[i]=p[i]+sum{g[j]|j in son[i]}。
      如果要自动搞坏i点,也就是说要把其中c[i]个g[j]替换成对应的f[j],可以对子结点按照f[j]-g[j]排序。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 #include<algorithm>
     5 typedef long long int64;
     6 const int64 inf=0x7fffffffffffffffll;
     7 inline int getint() {
     8     register char ch;
     9     while(!isdigit(ch=getchar()));
    10     register int x=ch^'0';
    11     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    12     return x; 
    13 }
    14 const int N=50001;
    15 std::vector<int> e[N];
    16 inline void add_edge(const int &u,const int &v) {
    17     e[u].push_back(v);
    18     e[v].push_back(u);
    19 }
    20 inline void init() {
    21     for(register int i=1;i<N;i++) {
    22         e[i].clear();
    23     }
    24 }
    25 int p[N],c[N];
    26 int64 f[N],g[N];
    27 inline bool cmp(const int &x,const int &y) {
    28     return f[x]-g[x]<f[y]-g[y];
    29 }
    30 void dp(const int &x,const int &par) {
    31     f[x]=g[x]=p[x];
    32     int64 sum=0;
    33     for(register std::vector<int>::iterator i=e[x].begin();i<e[x].end();i++) {
    34         if(*i==par) {
    35             e[x].erase(i);
    36             break;
    37         }
    38     }
    39     for(unsigned i=0;i<e[x].size();i++) {
    40         const int &y=e[x][i];
    41         dp(y,x);
    42         sum+=g[y];
    43     }
    44     f[x]+=sum;
    45     g[x]+=sum;
    46     std::sort(e[x].begin(),e[x].end(),cmp);
    47     if(c[x]<=(signed)e[x].size()+1) {
    48         for(register int i=0;i<c[x]-1;i++) {
    49             const int &y=e[x][i];
    50             sum+=f[y]-g[y];
    51         }
    52         g[x]=std::min(g[x],sum);
    53         if(c[x]<=(signed)e[x].size()) {
    54             const int &y=e[x][c[x]-1];
    55             sum+=f[y]-g[y];
    56             f[x]=std::min(f[x],sum);
    57         }
    58     }
    59 }
    60 int main() {
    61     for(register int T=getint();T;T--) {
    62         init();
    63         int n=getint();
    64         for(register int i=1;i<n;i++) {
    65             add_edge(getint(),getint());
    66         }
    67         for(register int i=1;i<=n;i++) {
    68             p[i]=getint();
    69         }
    70         for(register int i=1;i<=n;i++) {
    71             c[i]=getint();
    72         }
    73         dp(1,0);
    74         printf("%lld
    ",f[1]);
    75     }
    76     return 0;
    77 }
  • 相关阅读:
    CodeForces
    设计模式之装饰模式和代理模式区别与联系
    java反射 概念
    Java 反射详解 转载
    Spring--AOP 例子
    MD5加密
    面向对象编程思想(OOP)
    软件测试assert
    junit4.9测试用例 spring测试用例 Assert 注解
    断言
  • 原文地址:https://www.cnblogs.com/skylee03/p/7729288.html
Copyright © 2020-2023  润新知