• codevs1746 贪吃的九头龙


    【问题描述】
    传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落。
    有一天,有 M 个脑袋的九头龙看到一棵长有 N 个果子的果树,喜出望外,恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把 N 个果子分成 M 组,每组至少有一个果子,让每个头吃一组。
    这 M 个脑袋中有一个最大,称为“大头”,是众头之首, 它要吃掉恰好 K 个果子,而且 K 个果子中理所当然地应该包括唯一的一个最大的果子。 果子由 N-1根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝“走到”任何一个其他的果子。
    对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所有头吃掉的树枝的“难受值”之和。
    九头龙希望它的“难受值”尽量小,你能帮它算算吗?
    例如图 1 所示的例子中,果树包含 8 个果子,7 段树枝,各段树枝的“难受值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉 4 个果子,其中必须包含最大的果子。即 N=8,M=2,K=4:
    最大的果子大头吃 4 个果子,用实心点标识;小头吃 4 个果子,用空心点标识;九头龙的难受值为 4,因为图中用细边标记的树枝被大头吃掉了。
    【输入文件】
    输入文件 dragon.in 的第 1 行包含三个整数 N (1<=N<=300), M (2<=M<=N),K (1<=K<=N)。 N 个果子依次编号 1,2,...,N,且 最大的果子的编号总是 1。

    第 2行到第 N 行描述了果树的形态,每行包含三个整数 a (1<=a<=N), b (1<=b<=N),c (0<=c<=10 5 ),表示存在一段难受值为 c 的树枝连接果子 a 和果子 b。
    【输出文件】
    输出文件 dragon.out 仅有一行,包含一个整数,表示在满足“大头”的要求的前提下,九头龙的难受值的最小值。如果无法满足要求,输出-1。
    【样例输入】
    8 2 4
    1 2 20
    1 3 4
    1 4 13
    2 5 10
    2 6 12
    3 7 15
    3 8 5
    【样例输出】
    4
    【样例说明】
    该样例对应于题目描述中的例子。

     

     

    正解:树形DP

    解题报告:

      今天考试T4,居然是NOI原题。

      显然是一道树形DP,但是我们考虑记录的状态是什么:f[0、1][i][j]表示以i为根结点的子树中1号吃了j个并且i不选或者选的最小值。同时记忆化。

      直接分类讨论儿子结点选了多少个,总复杂度O(N^3)。

      代码如下:

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 using namespace std;
    14 typedef long long LL;
    15 const int MAXN = 311;
    16 LL inf;
    17 int n,m,k,ecnt;
    18 int first[MAXN],next[MAXN*2],to[MAXN*2];
    19 int brother[MAXN],son[MAXN],lian[MAXN][MAXN];
    20 bool vis[MAXN];
    21 LL f[2][MAXN][MAXN];
    22 
    23 inline int getint()
    24 {
    25        int w=0,q=0; char c=getchar();
    26        while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
    27        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
    28 }
    29 
    30 inline void down(int x,int fa){
    31     vis[x]=1;
    32     for(int i=first[x];i;i=next[i]) {
    33     int v=to[i]; if(vis[v]) continue;
    34     //printf("%d %d
    ",v,brother[v]); 
    35     brother[v]=son[x]; son[x]=v; down(v,x);
    36     }
    37 }
    38 
    39 inline LL dfs(int x,int fa,int remain,int flag){
    40     if(x==0) { if(remain==0) return 0; else return -1; }
    41     if(f[flag][x][remain]!=-1) return f[flag][x][remain];
    42     LL minl=inf,nowl,nowr,suan;
    43     for(int i=0;i<=remain;i++) {
    44     nowl=dfs(brother[x],fa,i,flag);
    45     if(nowl==remain) nowr=-1; 
    46     else nowr=dfs(son[x],x,remain-i-1,1);//
    47     
    48     /*if(nowl>=0) {    
    49       if(flag==1) { suan=nowl+nowr+lian[fa][x]; } else suan=nowl+nowr;   
    50       if(suan<minl) minl=suan;    }
    51     */
    52 
    53     if(nowl>=0 && nowr>=0) {
    54         if(flag==1) { suan=nowl+nowr+lian[fa][x]; } else suan=nowl+nowr;
    55         minl=min(minl,suan);
    56     } 
    57     nowr=dfs(son[x],x,remain-i,0);//不选
    58     /*if(nowl>=0) {
    59         if(flag==0 && m==2) suan=nowl+nowr+lian[fa][x]; else suan=nowl+nowr;
    60         minl=min(minl,suan);
    61         }*/
    62     if(nowl>=0 && nowr>=0) {
    63         if(flag==0 && m==2) suan=nowl+nowr+lian[fa][x]; else suan=nowl+nowr;
    64         minl=min(minl,suan);
    65     }
    66     }
    67     //printf("%d %d %d %d
    ",x,fa,remain,flag);
    68     if(minl==inf) f[flag][x][remain]=-inf; else f[flag][x][remain]=minl; 
    69     return f[flag][x][remain];
    70 }
    71 
    72 inline void work(){
    73     n=getint(); m=getint(); k=getint(); inf=1; for(int i=1;i<=60;i++) inf*=2;
    74     int x,y,z;
    75     for(int i=1;i<n;i++) {
    76     x=getint(); y=getint(); z=getint(); lian[x][y]=lian[y][x]=z;
    77     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
    78     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
    79     }
    80     if(m-1+k>n) { printf("-1"); return ; }
    81     down(1,0); memset(f,-1,sizeof(f));
    82     dfs(son[1],1,k-1,1);
    83     printf("%lld",f[1][son[1]][k-1]);
    84 }
    85 
    86 int main()
    87 {
    88   work();
    89   return 0;
    90 }
  • 相关阅读:
    适配器和外观模式
    命令模式
    单件模式
    工厂模式
    装饰者模式
    观察者模式(发布--订阅模式)
    设计模式之策略模式
    C#学习笔记15
    C#学习笔记14
    lucky的时光助理-2017.02
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5881813.html
Copyright © 2020-2023  润新知