蓝桥杯 算法提高 Trade on Verweggista 动态规划 java实现

问题描述
  自从Peter Stuyvesant和Abel Tasman的日子以后,荷兰商人已经周游世界来买卖商品。有一次在Verweggistan的贸易,但是它在很短的时间后就结束了。在读完这个故事之后你就明白了。
  在当时Verweggistan是非常受欢迎的,因为世界上只有那个地方的人知道怎样制作一个“prul”(或者“prullen”,荷兰语中的复数形式),并且如今只有很少的人知道什么是一个“prul”。
  “prul”是在工场里生产的。当一个“prul”做完的时候,它被包装在一个箱子里,然后放在之前生产的“prul”所装的箱子堆的上面。
  价格取决于生产“prul”所需要的时间。如果一切顺利,一个“prul”的价格会是1或者2弗罗林,但是在一个恶劣的日子,价格会很容易地上升到15弗罗林或者更高。“prul”在品质上没有什么差别,所有的“prul”具有相同的价值。
  在这些天,“prul”在荷兰的售价为每件10弗罗林。交通运输的费用是可以忽略的,因为“prul”无论如何都会作为额外的东西被装载到要航行的船上。当一个荷兰商人去Verweggistan时,他有一个明确的目的:买“prul”,在荷兰销售,并且最大化他的利润。不幸的是,Verweggistan地区对“prul”的交易方式使得这比某些人预想的更为复杂。
  有人认为这很简单,商人会买那些最便宜的“prul”,而那些售价比10弗罗林高的“prul”会一直不能出售。不幸的是,Verweggistan的所有工场按照一种奇怪的顺序销售“prul”。堆顶的箱子里的“prul”会最先销售,然后销售从顶上开始数的第二个箱子里的“prul”,以此类推。所以即使第五个箱子里的“prul”是最便宜的,商人也必须买它上面四个箱子里的“prul”才能得到它。
  正如你想象的那样,这使得商人通过购买正确的“prul”的组合来最大化他们的利润是相当难的。没有电脑帮助他们的优化,他们迅速彻底失去了交易“prul”的兴趣。
  在这个问题中,给你对几个工场里箱子堆的描述。你必须根据上面所给的限制,计算出一个商人通过购买箱子堆中的“prul”可以获得的最大利润。另外,你必须确定他需要买多少个“prul”才能获得最大利润。
  
输入格式
  输入文件包含多组测试数据。每个测试数据的第一行是一个整数w(1<=w<=50),该测试数据中工场的数目。
  接下来有w行,每行描述一个放“prul”的箱子堆。每行的第一个整数b(0<=b<=20),表示堆中的箱子数。接下来是b个正整数,表示堆中“prul”的价格(单位为弗罗林)。输入中箱子的顺序是从顶到底。
  输入数据终止于w=0,不再有后续的描述内容。
  
  
输出格式
  对于每组测试数据,输出测试点的编号(1,2…)。然后输出两行,第一行输出商人可以获得的最大利润。第二行输出为获得最大利润商人需要买的“prul”数量。如果这个数量不是唯一确定的,按照升序输出可能的值。如果有超过10种可能的取值,只输出10个最小的取值。
  
  
样例输入
1
6 12 3 10 7 16 5
2
5 7 3 11 9 10
9 1 2 3 4 10 16 10 4 16
0

样例输出
Workyards 1
Maximum profit is 8.
Number of pruls to buy: 4
Workyards 2
Maximum profit is 40.
Number of pruls to buy: 6 7 8 9 10 12 13

数据规模和约定
  1<=w<=50,0<=b<=20,输入文件保证测试点个数不超过10。

解题思路:
1、首先求出每个工厂的最大利润,再求出每个工厂取得最大利润的买法种类。
2、将第一个工厂得到的最小买法种类加上第二个工厂的最小买法种类只取前十
3、工厂总利润,直接取每个工厂的最大利润相加即可。

需要注意的点:输出有点坑,输出总利润最后有个.不要忘记加。


import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.TreeSet;

public class Trul {
    public static void main(String[] args) {
        Scanner sc=new Scanner((System.in));
        int M;//几个工厂
        int N=1;//第几个例子
        while((M=sc.nextInt())!=0){
            int[][] arr;//第几个工厂的最大利润值的最小买法种类
            int Max=0;//最大利润值
            arr=new int[M][10];
            for (int i = 0; i <M ; i++) {
                int w=sc.nextInt();//物品数量
                int sum=0;//用于计算最大利润值的临时变量
                int max=0;//第i个工厂的最大利润值
                int[] a=new int[w];
                for (int j = 0; j <w ; j++) {
                    sum+=(10-sc.nextInt());
                    a[j]=sum;
                    if(max<sum)
                        max=sum;
                }
                Max+=max;//计算总利润值
                int length=0;
                if(max==0)
                    arr[i][length++]=0;
                for (int j = 0; j <w&&length<10 ; j++) {
                    if(a[j]==max) {
                        arr[i][length++] = j + 1;
                    }
                }
                if(length<10)
                arr[i][length]=-1;//如果第i个工厂不足1种设置结束点
            }
            int[] amin=arr[0];//最小的十种取法,赋初值为第一个工厂的取法
            for (int i = 1; i <M ; i++) {
                TreeSet<Integer> qe=new TreeSet<>();//用TreeSet去重
                int j=0;
                while(j<10&&amin[j]!=-1){
                    if(j!=0&&amin[j]==0)
                        break;
                    int k=0;
                    while(k<10&&arr[i][k]!=-1){
                        qe.add(arr[i][k]+amin[j]); //添加前i行最小的十种取法
                        k++;
                    }
                    j++;
                }
                int length=0;
                for(int t:qe){
                    if(length==10)
                        break;
                    amin[length++]=t;//更新最小十种取法
                }
            }
            System.out.println("Workyards "+(N++));
            System.out.println("Maximum profit is "+Max+".");
            System.out.print("Number of pruls to buy: ");

            for (int i = 0; i <10 ; i++) {
                if((amin[i]==0&&i!=0)||amin[i]==-1)
                    break;
                else
                    System.out.print(amin[i]+" ");//输出取的种类
            }
            System.out.println();

        }
    }
}

友情提示:如果想copy代码通过蓝桥杯评测,需要将名字改为Main。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值