hrbust 1611 最强兵力【二维费用完全背包+分类处理】

本文介绍了一款基于《魔兽争霸》的游戏算法问题,通过三维资源管理和完全背包问题的空间优化策略,探讨了如何最大化攻击力的问题。文章给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最强兵力
Time Limit: 2000 MSMemory Limit: 65535 K
Total Submit: 33(17 users)Total Accepted: 18(16 users)Rating: Special Judge: No
Description

《魔兽争霸》,经典的即时策略游戏。在游戏里,要建造或者生产一个攻击单位,需要消耗金钱和木材,并且还占据一定的食物数量,有些攻击单位还需要建造其他建筑才能进行生产。

为了简化问题,我们修改一下,假设有三种能建造攻击单位的建筑,分别为A B C,其中,B只能在A建造之后才能建造,C只能在B建造之后才能建造,建造它们所需的金钱和木材分别为Ag Aw, Bg Bw, Cg CwAg为建造A所需的金钱,Aw为建造A所需的木材,依次类推。

这三种建筑生产不同的攻击单位,每个生产一个攻击单位,需要消耗金钱g,木材w,我们忽略食物的占据,每个单位有各自的攻击力,生产的攻击单位越多,单个攻击单位的攻击力越强,总体的攻击力就越强,总体的攻击力为所有攻击单位攻击力之和,现在假设每种攻击单位生产数量没有上限。

你现在只有金钱G和木头W,有N种攻击单位,它们分别产自不同的建筑。

如何安排这些资源,才能使得总的攻击力最强。

Input

有多组测试数据,对于每组测试数据,第一行为6个整数Ag Aw Bg Bw Cg Cw,为建造三种建筑的各自所需的金钱和木材花费,第二行为三个整数G  W  N,接下来有N行,每一行表示一种攻击单位的信息,包含四个整数gi wi ai digi为金钱花费wi为木材花费,ai为攻击力大小,di表示这个攻击单位从哪个建筑生产。

数据范围:0<=Ag,Aw,Bg,Bw, Cg,Cw<=100

1<=G<=1000, 1<=W<=100, N<=1001<=gi,wi,ai<=100di为大写字母ABC

处理到文件结束,测试数据不超过5组。

Output

对于每组测试数据,输出一行,包含一个整数,为最强的攻击力。


Sample Input
1 1 2 20 30 30
100 100 6
2 1 10 A
2 2 15 A
3 4 20 B
5 4 30 B
6 9 60 C
15 7 220 C
Sample Output
940
Source
计算机科学与技术学院2012级新生程序设计竞赛(正式赛)
Author
黄李龙@HRBUST

思路:


1、很明显的完全背包的模型。只不过其变化为费用从一维变化到二维。

那么我们可以设定dp【i】【j】【k】表示当前处理到第i种物品,其金钱容量为j,木材容量为k的最大攻击力。

根据完全背包空间优化,我们设定dp【j】【k】表示其金钱容量为j,木材容量为k的最大攻击力。

其状态转移方程:
dp【j】【k】=max(dp【j】【k】,dp【j-a【i】.g】【k-a【i】.w】+a【i】.ai);


2、因为只有三种建筑,而且必须按照A.B.C的顺序来建立。

那么我们直接分类讨论即可:

①只建立A的情况

②建立了A和B的情况

③全部都建立了的情况

那么我们此时跑三次二维费用完全背包。维护最大值即可、


Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct node
{
    int g,w,ai;
    char s[5];
}a[1515];
int dp[1020][120];
int main()
{
    int ag,aw,bg,bw,cg,cw;
    while(~scanf("%d%d%d%d%d%d",&ag,&aw,&bg,&bw,&cg,&cw))
    {
        int g,w,n;
        scanf("%d%d%d",&g,&w,&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%s",&a[i].g,&a[i].w,&a[i].ai,a[i].s);
        }
        int output=0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            if(a[i].s[0]!='A')continue;
            for(int j=a[i].g;j<g;j++)
            {
                for(int k=a[i].w;k<w;k++)
                {
                    dp[j][k]=max(dp[j][k],dp[j-a[i].g][k-a[i].w]+a[i].ai);
                }
            }
        }
        if(g>ag&&w>aw)output=max(output,dp[g-ag][w-aw]);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            if(a[i].s[0]=='C')continue;
            for(int j=a[i].g;j<g;j++)
            {
                for(int k=a[i].w;k<w;k++)
                {
                    dp[j][k]=max(dp[j][k],dp[j-a[i].g][k-a[i].w]+a[i].ai);
                }
            }
        }
        if(g>ag+bg&&w>aw+bw)output=max(output,dp[g-ag-bg][w-aw-bw]);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            for(int j=a[i].g;j<g;j++)
            {
                for(int k=a[i].w;k<w;k++)
                {
                    dp[j][k]=max(dp[j][k],dp[j-a[i].g][k-a[i].w]+a[i].ai);
                }
            }
        }
        if(g>ag+bg+cg&&w>aw+bw+cw)output=max(output,dp[g-ag-bg-cg][w-aw-bw-cw]);
        printf("%d\n",output);
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值