题解 HJ16 | #购物单#

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        //接收输入
        int money=in.nextInt();
        int num=in.nextInt();
        int[][] things=new int[num][3];
        for(int i=0,j=0;i<num;i++){
            things[i][j]=in.nextInt();j++;
            things[i][j]=in.nextInt();j++;
            things[i][j]=in.nextInt();j=0;
        }
        /*for(int i=0,j=0;i<5;i++){
        System.out.print(things[i][j]);j++;
        System.out.print(things[i][j]);j++;
        System.out.println(things[i][j]);j=0;
        }*/
        //建立一个总份数表,比如一个带有2个附件的主件,有四种可能,分别是0+1,0+2,0,0+1+2,带一个附件就是0,0+1,不带附件就是0
        //为此要先算出对应的可能数,建立一个新表
        int count=0;
        for(int i=0;i<num;i++){
            if (things[i][2]==0){
                count++;
                int j=0;
                for(;j<num;j++){
                    if(things[j][2]==i+1){
                        count++;break;
                    }                
                }
                for(;j<num;j++){
                    if(things[j][2]==i+1){
                        count+=2;break;
                    }                
                }
            }
        }//计算新表长度
        //System.out.print(count);
        int[][] list=new int[count][3];
        count=0;
        for(int i=0;i<num;i++){
            if (things[i][2]==0){
                list[count][0]=things[i][0];//价格
                list[count][1]=things[i][0]*things[i][1];//满意度
                list[count][2]=1;
                count++;
                int j=0;
                for(;j<num;j++){
                    if(things[j][2]==i+1){
                        list[count][0]=things[j][0]+things[i][0];//价格
                        list[count][1]=things[j][0]*things[j][1]+things[i][0]*things[i][1];//满意度
                        list[count-1][2]=2;
                        count++;   
                        j++;                     
                        break;
                    }                
                }
                for(;j<num;j++){
                    if(things[j][2]==i+1){
                        list[count][0]=things[j][0]+list[count-2][0];//价格
                        list[count][1]=things[j][0]*things[j][1]+list[count-2][1];//满意度
                        list[count-2][2]=4;
                        count++;      
                        list[count][0]=things[j][0]+list[count-2][0];//价格
                        list[count][1]=things[j][0]*things[j][1]+list[count-2][1];//满意度            
                        count++;
                        break;
                    }                
                }
            }
        }
        int[] val=new int[money/10+1];
        for(int i=0;i<count;i++){
            if(list[i][2]!=0){
                if(list[i][2]==1){
                for(int j=money/10;j>=list[i][0]/10;j--)
                val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);
                }
                else if(list[i][2]==2){
                    int j=money/10;
                    for(;j>=list[i+1][0]/10;j--)
                        val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]);
                    for(;j>=list[i][0]/10;j--)
                        val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);
                }
                else if(list[i][2]==4){
                    int j=money/10;
                    for(;j>=list[i+3][0]/10;j--)
                        val[j]=Math.max(Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]),val[j-list[i+3][0]/10]+list[i+3][1]);
                    if(list[i+1][0]>=list[i+2][0]){
                        for(;j>=list[i+1][0]/10;j--)
                            val[j]=Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]);
                        for(;j>=list[i+2][0]/10;j--)
                            val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+2][0]/10]+list[i+2][1]);
                    }
                    else{
                        for(;j>=list[i+2][0]/10;j--)
                            val[j]=Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]);
                        for(;j>=list[i+1][0]/10;j--)
                            val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]);
                }
                    for(;j>list[i][0]/10;j--)
                        val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);
                }
            }
        }
        System.out.print(val[money/10]);

    }
}

思路是动态规划,01背包问题,但是这个相比于正常的01背包问题又多了个主附件问题

可以按照主键进行分类

一个主键有一种,一个主键带一个附件有,主,主+附俩种,而一个主键+俩个附件有 主,主+附1,主+附2,主+附1+附2,四种

我先算出有多少种可能

    //建立一个总份数表,比如一个带有2个附件的主件,有四种可能,分别是0+1,0+2,0,0+1+2,带一个附件就是0,0+1,不带附件就是0
    //为此要先算出对应的可能数,建立一个新表
    int count=0;
    for(int i=0;i<num;i++){
        if (things[i][2]==0){
            count++;
            int j=0;
            for(;j<num;j++){
                if(things[j][2]==i+1){
                    count++;break;
                }                
            }
            for(;j<num;j++){
                if(things[j][2]==i+1){
                    count+=2;break;
                }                
            }
        }
    }//计算新表长度

之后我建立了一个新表,这个表长度为之前算的可能性,宽度为3,第一个放重量,第二个放满意度,第三个放这个是哪一种

如果是单主则为1,如果是主+1附为2,如果是主+2附则为4

比如为4的

第i行放主的重量和满意度

第i+1行放主+1附的重量和满意度

第i+2行放主+2附的重量和满意度

第i+3行放主+1+2附的重量和满意度

int[][] list=new int[count][3];

count=0;

for(int i=0;i<num;i++){

if (things[i][2]==0){

list[count][0]=things[i][0];//价格

list[count][1]=things[i][0]*things[i][1];//满意度

list[count][2]=1;

count++;

int j=0;

for(;j<num;j++){

if(things[j][2]==i+1){

list[count][0]=things[j][0]+things[i][0];//价格

list[count][1]=things[j][0]*things[j][1]+things[i][0]*things[i][1];//满意度

list[count-1][2]=2;

count++;

j++;

break;

}

}

for(;j<num;j++){

if(things[j][2]==i+1){

list[count][0]=things[j][0]+list[count-2][0];//价格

list[count][1]=things[j][0]*things[j][1]+list[count-2][1];//满意度

list[count-2][2]=4;

count++;

list[count][0]=things[j][0]+list[count-2][0];//价格

list[count][1]=things[j][0]*things[j][1]+list[count-2][1];//满意度

count++;

break;

}

}

}

}

之后创建一个动态规划表 int[] val=new int[money/10+1];长度为money/10这个表初始全为0

遇到单主,大于这个主的重量的部分,遍历一遍,val[j]的值在表原本的值和val[j-list[i][0]/10]+list[i][1]取最大的那个

,j表示的是重量,val[j-list[i][0]/10]的意思是减去这个件的满意度最大值,再加上这个件的满意度

if(list[i][2]==1){

for(int j=money/10;j>=list[i][0]/10;j--)

val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);

}

后面遇到主+1附,在大于主+附重量时,从val[j] 原最大满意度,val[j-list[i][0]/10]+list[i][1]) 减去主重量的最大满意度+主的满意度,val[j-list[i+1][0]/10]+list[i+1][1] 减去主+附的重量最大满意+主+附的满意度中选择最大的

在小于主+附,又大于主,则和之前一样

else if(list[i][2]==2){

int j=money/10;

for(;j>=list[i+1][0]/10;j--)

val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]);

for(;j>=list[i][0]/10;j--)

val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);

}

主+2附,又分为大于主+2附,大于主+附件重的那个,大于主+附件轻的那个,大于主四种

else if(list[i][2]==4){

int j=money/10;

for(;j>=list[i+3][0]/10;j--)

val[j]=Math.max(Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]),val[j-list[i+3][0]/10]+list[i+3][1]);

if(list[i+1][0]>=list[i+2][0]){

for(;j>=list[i+1][0]/10;j--)

val[j]=Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]);

for(;j>=list[i+2][0]/10;j--)

val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+2][0]/10]+list[i+2][1]);

}

else{

for(;j>=list[i+2][0]/10;j--)

val[j]=Math.max(Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]),val[j-list[i+2][0]/10]+list[i+2][1]);

for(;j>=list[i+1][0]/10;j--)

val[j]=Math.max(Math.max(val[j],val[j-list[i][0]/10]+list[i][1]),val[j-list[i+1][0]/10]+list[i+1][1]);

}

for(;j>list[i][0]/10;j--)

val[j]=Math.max(val[j],val[j-list[i][0]/10]+list[i][1]);

}

}

最后输出最大的满意度:System.out.print(val[money/10]);

#华为od题库#
华为OD笔试库讲解,JAVA版 文章被收录于专栏

随便发发而已

全部评论

相关推荐

头像
10-15 22:27
已编辑
门头沟学院 C++
罗格镇的小镇做题家:我投了hr打电话来说学历太低了不符合要求,建议投荣耀,结果荣耀也投了一定水花没有,非本211硕
投递华为等公司10个岗位
点赞 评论 收藏
分享
听说改名字就能收到offer哈:Radis写错了兄弟
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务