• JSOI 2008 【魔兽地图】


    其实这题是我从noip前就开始做的。。。那个时候打的Pascal,一直TLE,转了C++之后我又写了一遍,A了。。。

    辛酸史:

                          

    题目描述:

    DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars。

    DotR里面的英雄只有一个属性——力量。他们需要购买装备来提升自己的力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力量值之和。装备分为基本装备和高级装备两种。基本装备可以直接从商店里面用金币购买,而高级装备需要用基本装备或者较低级的高级装备来合成,合成不需要附加的金币。装备的合成路线可以用一棵树来表示。

    比如,Sange and Yasha的合成需要Sange,Yasha和Sange and Yasha Recipe Scroll三样物品。其中Sange又要用Ogre Axe, Belt of Giant Strength和 Sange Recipe Scroll合成。每件基本装备都有数量限制,这限制了你不能无限制地合成某些性价比很高的装备。

    现在,英雄Spectre有M个金币,他想用这些钱购买装备使自己的力量值尽量高。你能帮帮他吗?他会教你魔法Haunt(幽灵附体)作为回报的。

    数据范围:物品数(n)<=51,金币数(m)<=2000,限购数量(limit)<=100。

    思路分析:

    可以说是一道树上背包DP吧。

    观察题目,注意到:限购数量是题目的关键,对于一个物品,它合成几件,或是把几件用于父亲装备的合成,是题目恶心的地方,既然这样的话我们就把它设计到状态里面。然后再看看数据范围,限购小于等于100——很明显了,出题人就是想让我们把限购数量放进状态里面。再和普通的背包结合一下,得到状态,f[u][i][j]表示:对于以u为根的子树,在以u为根的子树上,我们投入i个金币,并且把j个物品u用于父亲装备的合成,以u为根的子树能产生的最大力量值

    然后我们还需要一个g数组来辅助f数组的转移。g[i][j]表示:对于u的前i个儿子装备,在以它们为根的子树中投入j个金币,能得到的最大力量值。

    转移时我们需要枚举的很重要的一环就是:制作几个u装备,从而让整个转移能够顺利地进行下去,我们把它设为l。

    得到g数组的转移:g[i][j]=max(g[i][j],g[i-1][j-k]+f[v][k][l*need])       其中v为u的第i个儿子,而need则为制作一个装备u需要几个装备v,k为在以v为根的子树中花费k个金币。

    通过g数组的转移,继而得到f数组的转移:f[u][i][j]=max(f[u][i][j],g[siz[u]][i]+w[u]*(l-j))       其中siz[u]表示u有几个儿子。

    最后求答案的时候我们又需要一个dp数组来求解。(嗯,没错,一道题目,三个背包dp,我也不得不佩服出题人了——你是真TM的毒瘤!

    最后这个就是最简单的背包dp了(如果这个都想不到的话,建议你前往xx省xx市实验学校,和某张姓老师学习一段时间)

    状态dp[i][j],表示前i个“终极装备”(终极装备就是无法用于合成的装备),花费j个金币,能得到的最大力量值。转移的时候枚举一下在第i个装备上花费多少金币就可以了,具体不懂的话还是看代码吧,太简单了,也不想多讲了。

    代码实现:

    #include<bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int f[55][2005][105],g[55][2005],dp[55][2005];
    int a[55][55],need[55][55],limit[55],cost[55],w[55],siz[55];
    bool root[55],son[55];
    int n,m;
    void dfs(int u){
        if (!son[u]){
            limit[u]=min(limit[u],m/cost[u]);
            for (int i=0;i<=limit[u];i++)
                for (int j=0;j<=i;j++)
                    f[u][i*cost[u]][j]=w[u]*(i-j);
            return;
        }
        limit[u]=inf;
        for (int i=1;i<=siz[u];i++){
            dfs(a[u][i]);
            cost[u]+=cost[a[u][i]]*need[u][i];
            limit[u]=min(limit[u],limit[a[u][i]]/need[u][i]);
        }
        limit[u]=min(limit[u],m/cost[u]);
        memset(g,-0x3f,sizeof(g));
        g[0][0]=0;
        for (int l=limit[u];l>=0;l--){                          //这里倒着枚举l,是为了避免多次给g数组赋初值
            for (int i=1;i<=siz[u];i++)
                for (int j=0;j<=m;j++)
                    for (int k=0;k<=j;k++)
                        g[i][j]=max(g[i][j],g[i-1][j-k]+f[a[u][i]][k][l*need[u][i]]);
            for (int i=0;i<=l;i++)
                for (int j=0;j<=m;j++)
                    f[u][j][i]=max(f[u][j][i],g[siz[u]][j]+w[u]*(l-i));
        }
    }
    int main(){
        memset(f,-0x3f,sizeof(f));
        scanf("%d%d",&n,&m);
        int nn,ans=0;
        for (int i=1;i<=n;i++){
            scanf("%d",&w[i]);
            char ch[3]; scanf("%s",&ch);
            if (ch[0]=='A'){
                scanf("%d",&nn);
                for (int j=1;j<=nn;j++) scanf("%d%d",&a[i][j],&need[i][j]),root[a[i][j]]=true;
                son[i]=true; siz[i]=nn;
            } else scanf("%d%d",&cost[i],&limit[i]);
        }
        int now=0;
        for (int i=1;i<=n;i++)
            if (!root[i]){
                dfs(i); now++;
                for (int j=0;j<=m;j++)
                    for (int k=0;k<=j;k++)
                        dp[now][j]=max(dp[now][j],dp[now-1][j-k]+f[i][k][0]);
            }
        for (int i=0;i<=m;i++) ans=max(ans,dp[now][i]);
        printf("%d
    ",ans);
        return 0;
    } 
  • 相关阅读:
    接口调试之Postman 使用方法详解
    用Vue2仿京东省市区三级联动效果
    高德地图JS API获取经纬度,根据经纬度获取城市
    js 格式化数字,格式化金额:
    CSS Media媒体查询使用大全,完整媒体查询总结
    最新手机号正则表达式 java 、javascript版正则表达式验证是否为11位有效手机号码
    JavaScript 实现textarea限制输入字数, 输入框字数实时统计更新,输入框实时字数计算移动端bug解决
    在上线项目中,用Vue写一个星级评价
    new Date()设置日期在IOS的兼容问题
    javascript 省市区三级联动 附: json数据
  • 原文地址:https://www.cnblogs.com/WR-Eternity/p/9967550.html
Copyright © 2020-2023  润新知