zoukankan      html  css  js  c++  java
  • codevs 1746 贪吃的九头龙 2002年NOI全国竞赛

    1746 贪吃的九头龙

     

    2002年NOI全国竞赛

     时间限制: 2 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
     
     
     
    题目描述 Description

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

    输入描述 Input Description

    输入文件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<=105),表示存在一段难受值为c的树枝连接果子a和果子b。

    输出描述 Output Description

    输出文件dragon.out 仅有一行,包含一个整数,表示在满足“大头”的要求
    的前提下,九头龙的难受值的最小值。如果无法满足要求,输出-1。

    样例输入 Sample Input

    8 2 4
    1 2 20
    1 3 4
    1 4 13
    2 5 10
    2 6 12
    3 7 15
    3 8 5

    样例输出 Sample Output

    4

    数据范围及提示 Data Size & Hint

    该样例对应于题目描述中的例子。

    /*
    第一遍交全TLE......
    原因是初始化错了
    又把f数组(记忆化搜索用)初始化为-1然后>=0时return就不超时了
    得分70分
    */
    #include<iostream>#include<cstdio>#include<cstring>#define maxn 310#define bignum 1000000000using namespace std;int n,m,w,ch[maxn][3],first[maxn],topt,fa[maxn],f[maxn][2][maxn],v[maxn][maxn],ans=bignum;struct edge
    {
        int from;
        int to;
        int val;
        int next;
    }e[maxn*2];void add(int x,int y,int z)
    {
        topt++;
        e[topt].from=x;
        e[topt].to=y;
        e[topt].val=z;
        e[topt].next=first[x];
        first[x]=topt;
    }void build(int x)
    {
        for(int i=first[x];i;i=e[i].next)
        {
            int t=e[i].to;
            if(!fa[t])
            {
                fa[t]=x;
                if(!ch[x][1])
                ch[x][1]=t;
                else
                {
                    int now=ch[x][1];
                    while(ch[now][2])now=ch[now][2];
                    ch[now][2]=t;
                }
                build(t);
            }
        }
    }
    int dfs(int now,int p,int sum)//now当前节点,p表示now的父亲选没选,sum表示最大头还要吃几个
    {
        int i,j,k;
        if(f[now][p][sum]!=-1)return f[now][p][sum];
        if(sum==0)return 0;
        if(now==0)return bignum;
        int minn=bignum;
        for(i=0;i<=sum;i++)//不选这个
            minn=min(minn,dfs(ch[now][1],0,i)+dfs(ch[now][2],p,sum-i));
        for(i=0;i<=sum-1;i++) //选这个 
        {
            int tot;
            if(p==1)tot=v[now][fa[now]];
            else tot=0;
            tot+=dfs(ch[now][1],1,i)+dfs(ch[now][2],p,sum-1-i);
            minn=min(minn,tot);
        }
        f[now][p][sum]=minn;
        return f[now][p][sum];
    }int main()
    {
        int i,j,k;
        scanf("%d%d%d",&n,&m,&w);
        if(n-w<m-1)
        {
            printf("-1
    ");
            return 0;
        }
        memset(f,-1,sizeof(f));
        for(i=1;i<=n-1;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            v[x][y]=z;
            v[y][x]=z;
            add(x,y,z);
            add(y,x,z);
        }
        fa[1]=1;
        build(1);
        for(i=0;i<=w-1;i++)
        ans=min(ans,dfs(ch[1][1],1,i)+dfs(ch[1][2],1,w-1-i));
        printf("%d
    ",ans);
        return 0;
    }
    /*
    考虑m==2的情况
    又加了一个新的函数find()
    大体上和上面的函数一样
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 310
    #define bignum 1000000000
    using namespace std;
    int n,m,w,xxx,ch[maxn][3],first[maxn],topt,fa[maxn],f[maxn][2][maxn],v[maxn][maxn],ans=bignum;
    struct edge
    {
        int from;
        int to;
        int val;
        int next;
    }e[maxn*2];
    void add(int x,int y,int z)
    {
        topt++;
        e[topt].from=x;
        e[topt].to=y;
        e[topt].val=z;
        e[topt].next=first[x];
        first[x]=topt;
    }
    void build(int x)
    {
        for(int i=first[x];i;i=e[i].next)
        {
            int t=e[i].to;
            if(!fa[t])
            {
                fa[t]=x;
                if(!ch[x][1])
                ch[x][1]=t;
                else
                {
                    int now=ch[x][1];
                    while(ch[now][2])now=ch[now][2];
                    ch[now][2]=t;
                }
                build(t);
            }
        }
    }
    int dfs(int now,int p,int sum)
    {
        int i,j,k;
        if(f[now][p][sum]!=-1)return f[now][p][sum];
        if(sum==0)return 0;
        if(now==0)return bignum;
        int minn=bignum;
        for(i=0;i<=sum;i++)//最大头不选这个
            minn=min(minn,dfs(ch[now][1],0,i)+dfs(ch[now][2],p,sum-i));
        for(i=0;i<=sum-1;i++)//最大头选这个
        {
            int tot;
            if(p==1)tot=v[now][fa[now]];
            else tot=0;
            tot+=dfs(ch[now][1],1,i)+dfs(ch[now][2],p,sum-1-i);
            minn=min(minn,tot);
        }
        f[now][p][sum]=minn;
        return f[now][p][sum];
    }
    int find(int now,int p,int sum)
    {
        int i,j,k;
        if(f[now][p][sum]!=-1)return f[now][p][sum];
        if(now==0&&sum>0)return bignum;
        else if(now==0&&sum==0)return 0;
        int minn=bignum;
        for(i=0;i<=sum;i++)//最大头不选这个 
        {
            int tot;
            if(p==0)tot=v[now][fa[now]];
            else tot=0;
            tot+=find(ch[now][1],0,i)+find(ch[now][2],p,sum-i);
            minn=min(minn,tot);
        }   
        for(i=0;i<=sum-1;i++)//最大头选这个 
        {
            int tot;
            if(p==1)tot=v[now][fa[now]];
            else tot=0;
            tot+=find(ch[now][1],1,i)+find(ch[now][2],p,sum-1-i);
            minn=min(minn,tot);
        }
        f[now][p][sum]=minn;
        return f[now][p][sum];
    }
    int main()
    {
        int i,j,k;
        scanf("%d%d%d",&n,&m,&w);
        if(n-w<m-1)
        {
            printf("-1
    ");
            return 0;
        }
        memset(f,-1,sizeof(f));
        for(i=1;i<=n-1;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            v[x][y]=z;
            v[y][x]=z;
            add(x,y,z);
            add(y,x,z);
        }
        fa[1]=1;
        build(1);
        if(m==2)
        {
            for(i=0;i<=w-1;i++)
              ans=min(ans,find(ch[1][1],1,i)+find(ch[1][2],1,w-1-i));
            printf("%d
    ",ans);
            return 0;
        }
        for(i=0;i<=w-1;i++)
            ans=min(ans,dfs(ch[1][1],1,i)+dfs(ch[1][2],1,w-1-i));
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    PAT 1088. Rational Arithmetic
    PAT 1087. All Roads Lead to Rome
    PAT 1086. Tree Traversals Again
    PAT 1085. Perfect Sequence
    PAT 1084. Broken Keyboard
    PAT 1083. List Grades
    PAT 1082. Read Number in Chinese
    求最大公因数
    [转载]Latex文件转成pdf后的字体嵌入问题的解决
    [转载]Matlab有用的小工具小技巧
  • 原文地址:https://www.cnblogs.com/dingmenghao/p/5776804.html
Copyright © 2011-2022 走看看