ZOJ刷题1013 C++

        题目一开始介绍了挺过故事背景的,但是身为一个无情的刷题机器人还是都跳过去了没怎么看。好像大概是意思是公主要救国王,于是要进行一场诺曼底登陆。现在我们要用船运三种装备,问这么运使得装备防御力最大化。

题目

有三种装备(头盔,护甲,鞋子),他们有重量,大小,防御力。分别记为S,W,D

然后三种装备个C1,C2,C3个可以组成套装,套装防御力会比原来的大(原来的防御力不在计算)

然后船有载重和空间。

求最多可以运达多少防御力。

输入格式为

n               //船的数量,若输入0表示结束

w1,s1,d1    //头盔的重量,占地大小,防御力

w2,s2,d2   //护甲的重量,占地大小,防御力

w3,s3,d3   //鞋子的重量,占地大小,防御力

c1,c2,c3,d4   //组成套装需要c1个头盔,c2个护甲,c3个鞋子。套装防御力d4

D1,S1     //第一艘船的载重,空间

D2,S2     //第一艘船的载重,空间

..........      //其他船的载重,空间

 

解题

       这道题的重点是如何拿装备的问题,对于任何以知两个装备的数量,则第三个装备的数量是唯一固定的。所以我们可以用一个二维数组来存储装备的选择,记为dp[i][j]=x。其中i为头盔的数量,j为护甲的数量,x则是鞋子的数量。对于船,因为他只有两个属性,我们可以构建一个car[2][n]的数组来存储,其中car[0]表示船的载重, car[1]表示空间。car[?][x]表示第几艘。

对于任意一辆车j,他可以拿的头盔是最大数量是

min(car[0][j]/w1,car[1][j]/s1)。因此对于所有车,我们可以知道装备i可以携带的最大值,如下公式。

 

 这样我们就知道了每个装备的取值范围(0~maxi),要知道防御力的最高值并不是再某个装备最多的时候一定可以达到的,所以我们要设计一个循环结构,分别储存拿了i个头盔,j个护甲之后,还可以拿的鞋子数量,就是给每一个dp[i][j]写入数据。代码如下(再下列代码里,我们补充一个dp2[][]来存储最终答案,dp[][]起到暂时的作用)

int max_h=0;          //头盔的最大值
int max_a=0;          //护甲的最大值
int k=0;             //k+1是第几辆车
while(k<n)
{
    for(int i=0;i<=max_h;i++)
        for(int j=0;j<=max_a;j++)
            dp[i][j]=dp2[i][j];             //dp2[][]存储前k辆车的最中数据,dp[][]
    int max_hk=min(car[0][k]/w1,car[1][k]/s1);   //第k辆车可以拿的最多的头盔数
    for(int i =0;i<=max_hk;i++)
    {
        int ra_w=car[0][k]-i*w1;            //第k辆车可以拿了i个头盔后还剩的重量和空间,以及再这种空间下还可以拿的最多盔甲数
        int ra_s=car[1][k]-i*s1;
        int max_ak=min(ra_w/w2,ra_s/s2);
        for(int j=0;j<=max_ak;j++)
        {
            int rb_w=ra_w-j*w2;
            int rb_s=ra_s-j*s2;
            int max_bk=min(rb_w/w3,rb_s/s3);   //第k辆车可以拿了i个头盔和j个护甲后还剩的重量和空间,以及再这种空间下还可以拿的最多鞋子数
            for(int x=0;x<=max_h;x++)
                for(int y=0;y<=max_a;y++)
                    if(dp[x][y]>=0 && dp[x][y]+max_bk>=dp2[x+i][y+j])   //出现了可以拿过多鞋子的方案
                        dp2[x+i][y+j]=dp[x][y]+max_bk;
            
        }
    }
max_h+=min(car[0][k]/w1,car[1][k]/s1);     //最多可拿数量累加
max_a+=min(car[0][k]/w2,car[1][k]/s2);
k++;
}

这个代码写出来之后就差不多了,剩下的就是一个防御力计算函数

int count(int h,int a,int b)
{
    int comb=min(min(h/c1,a/c2),b/c3);
    return comb*d4+(h-comb*c1)*d1+(a-comb*c2)*d2+(b-comb*c3)*d3;
}

以及最终结果和输出

int ans=0
for(int i=0;i<=max_h;i++)
    for(int j=0;j<=max_a;j++)
        if(dp2[i][j]>=0)
        {
            int temp=count(i,j,dp2[i][j]);
            if(temp>ans) ans=temp;
        }
if(cas>0) puts("");  //cas 记录案例数
    cout<<"Case "<<++cas<<':'<<ans;

最后再补入一个初始化功能的步骤就行(用memse还是for再这道题里的数度好像差不多)

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int manx=501;
int dp[manx][manx],dp2[manx][manx];  //dp[i][j]=x mean we can put i helmt ,j armors and x boots
int car[2][manx];   //car[0]=wieght ,[1]=size
int w1,s1,d1,       //the weight,size,defend of helms
    w2,s2,d2,       //armors
    w3,s3,d3,       //boots
    c1,c2,c3,d4;    //the needed num of a comb and d4 is the defend of a comb
int min(int a,int b)
{
    return a<b? a:b;
}
int count(int h,int a,int b)
{
    int comb=min(min(h/c1,a/c2),b/c3);
    return comb*d4+(h-comb*c1)*d1+(a-comb*c2)*d2+(b-comb*c3)*d3;
}

int main()
{
    int n;
    int cas=0;
    while(cin>>n && n)
    {
        cin>>w1>>s1>>d1
            >>w2>>s2>>d2
            >>w3>>s3>>d3
            >>c1>>c2>>c3>>d4;
        int max_h=0;          //头盔的最大值
        int max_a=0;          //护甲的最大值
        int k=0;
        memset(dp,-1,sizeof(dp));
        memset(dp2,-1,sizeof(dp2));
        for(int i=0;i<n;i++)    //输入车的数据
            cin>>car[0][i]>>car[1][i];
        dp2[0][0]=0;
        while(k<n)
        {
            for(int i=0;i<=max_h;i++)
                for(int j=0;j<=max_a;j++)
                    dp[i][j]=dp2[i][j];             //dp2[][]存储前k辆车的最中数据,dp[][]
            int max_hk=min(car[0][k]/w1,car[1][k]/s1);   //第k辆车可以拿的最多的头盔数
            for(int i =0;i<=max_hk;i++)
            {
                int ra_w=car[0][k]-i*w1;            //第k辆车可以拿了i个头盔后还剩的重量和空间,以及再这种空间下还可以拿的最多盔甲数
                int ra_s=car[1][k]-i*s1;
                int max_ak=min(ra_w/w2,ra_s/s2);
                for(int j=0;j<=max_ak;j++)
                {
                    int rb_w=ra_w-j*w2;
                    int rb_s=ra_s-j*s2;
                    int max_bk=min(rb_w/w3,rb_s/s3);   //第k辆车可以拿了i个头盔和j个护甲后还剩的重量和空间,以及再这种空间下还可以拿的最多鞋子数
                    for(int x=0;x<=max_h;x++)
                        for(int y=0;y<=max_a;y++)
                            if(dp[x][y]>=0 && dp[x][y]+max_bk>=dp2[x+i][y+j])   //出现了可以拿过多鞋子的方案
                                dp2[x+i][y+j]=dp[x][y]+max_bk;
                }
            }
            max_h+=min(car[0][k]/w1,car[1][k]/s1);     //最多可拿数量累加
            max_a+=min(car[0][k]/w2,car[1][k]/s2);
            k++;
        }
    int ans=0;
    for(int i=0;i<=max_h;i++)
        for(int j=0;j<=max_a;j++)
            if(dp2[i][j]>=0)
            {
                int temp=count(i,j,dp2[i][j]);
                if(temp>ans) ans=temp;
            }
    if(cas>0) puts("");
    printf("Case %d: %d\n", ++cas, ans);
    }
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值