[蓝桥杯][算法提高 ADV-250]Trade on Verweggistan(Java)(DFS)

算法提高 Trade on Verweggistan  

时间限制:1.0s   内存限制:128.0MB

    

问题描述

  自从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<=w<=50,0<=b<=20,,将可能买入的货物选择算成了20*50=1000,结果数组越界,其实是21^50

③自己定义的变量太随意,记混,导致错误一片,越改越乱

④定义了很多没必要的变量,导致空间占用太多,也很乱。

⑤当最大利润为零时,不买也是一种情况,,还有考虑最大利润为负数 和 数量重复的时候。

解题思路:

这题说起来很简单,创建一个二维数组,用来存储第几个工厂获得最大利润时需要买入多少产品,然后创建一个TreeSet用来对dfs产生的所有情况去重和排序,取出前十个(大于十个,小于十个就取所有)。

Java代码:

import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main {
	static int[][] wMaxProAndNum;//a w's max profit and numbers
	static int[][] resMaxProAndNum=new int[11][11];//res's max profit and numbers
	static int id=1,w;
	static Set<Integer> set;
	static int[] resNumLast=new int[11];
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int[] pro = new int[21];
		while((w=cin.nextInt())!=0) {
			wMaxProAndNum=new int[w+1][21];
			for(int curw=1;curw<=w;curw++) {
				int b=cin.nextInt();
				int bNum=1;
				for(int curb=1;curb<=b;curb++) {
					pro[curb] = pro[curb-1] + 10 - cin.nextInt();
					wMaxProAndNum[curw][0]=wMaxProAndNum[curw][0]>pro[curb]?wMaxProAndNum[curw][0]:pro[curb];
				}
				if(wMaxProAndNum[curw][0]==0) wMaxProAndNum[curw][bNum++]=0;
				for(int curb=1;curb<=b;curb++) {
					if(pro[curb]==wMaxProAndNum[curw][0]) 
						wMaxProAndNum[curw][bNum++]=curb;
				}
				resMaxProAndNum[id][0]+=wMaxProAndNum[curw][0];
				wMaxProAndNum[curw][0]=bNum;
			}
			set=new TreeSet<>();
			dfs(1,new int[w+1]);
			for(int s:set) {
				resMaxProAndNum[id][++resNumLast[id]]=s;
				if(resNumLast[id]==10)break;
			}
			id++;
		}
		for(int curid=1;curid<id;curid++) {
			System.out.println("Workyards "+curid);
			System.out.println("Maximum profit is "+resMaxProAndNum[curid][0]+".");
			System.out.print("Number of pruls to buy:");
			for(int maxb=1;maxb<=resNumLast[curid];maxb++) {
				System.out.print(" "+resMaxProAndNum[curid][maxb]);
			}
			System.out.println("");
		}
		cin.close();
	}
	static void dfs(int curw,int[] wNum) {
		if(curw>w) {
			int res=0;
			for(int x=1;x<curw;x++) {
				res+=wNum[x];
			}
			set.add(res);
			return;
		}
		int len=wMaxProAndNum[curw][0];
		if(len==1) {
			dfs(curw+1, wNum);
		}
		else for(int curNum=1;curNum<len;curNum++) {
			wNum[curw]=wMaxProAndNum[curw][curNum];
			dfs(curw+1, wNum);
		}
	}
}

测试结果截图:

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值