算法笔记_103:蓝桥杯练习 算法提高 金明的预算方案(Java)
目录
1 问题描述
主件 | 附件 |
电脑 | 打印机,扫描仪 |
书柜 | 图书 |
书桌 | 台灯,文具 |
工作椅 | 无 |
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j_1,j_2,……,j_k,则所求的总和为:
v[j_1]*w[j_1]+v[j_2]*w[j_2]+ …+v[j_k]*w[j_k]。(其中*为乘号)
请你帮助金明设计一个满足要求的购物单。
N m
(其中N(<32000)表示总钱数,m(<60)为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数
v p q
(其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
2 解决方案
本题考查动态规划法的运用,这几天做的难题几乎都是动态规划题,而且搞了几个小时能拿满分也很少,这题最终结果只拿了70分,原因有三组数据运行错误,以下代码仅供参考,若有同学路过,指出错误,不胜感激~
首先,说一下解答这题的思想:该题是背包问题的变种,背包问题中状态转移方程为F(i, j) =max(F(i - 1, j),F(i - 1, j - w) + value),其中j >= w,否则F(i, j) = F(i - 1, j)。这题的核心变化,就是后面新增的物品i可能是前面物品i - k的附件,购买附件就必须先买主件,所以得要考虑前面已经得到的最优解中是否已经购买过了该主件。
那么,怎样解决此主件是否被购买的问题?那就是,把附件考虑到主件中,当后面新增一个物品i,该物品是附件时,直接令F(i, j) = F(i - 1, j),相当于跳过附件i。
把附件考虑到主件的方法:
当遇到一个物品i,其是主件时(PS:题目规定,每个主件可以有0个、1个或2个附件),那么,具体购买有以下四种购买情况:
(1)仅仅购买主件
(2)购买主件和附件1
(3)购买主件和附件2
(4)购买主件和附件1和附件2
具体代码如下:
import java.util.Scanner; public class Main { static class good { //物品内部类
public int v; //物品的价格
public int p; //物品的重要度
public int q;
public int a1 = 0; //附件1的编号
public int a2 = 0; //附件2的编号 good(int v, int p, int q) {
this.v = v;
this.p = p;
this.q = q;
} public void setA1(int a1) {
this.a1 = a1;
} public void setA2(int a2) {
this.a2 = a2;
}
} public int getMax(int a, int b) {
return a > b ? a : b;
} public void printResult(int N, good[] A) {
int[][] dp = new int[A.length][N + 1];
for(int i = 1, len = A.length;i < len;i++) {
int v = -1, v1 = -1, v2 = -1, v3 = -1, tempDp = -1,
tempDp1 = -1, tempDp2 = -1, tempDp3 = -1;
v = A[i].v;
tempDp = v * A[i].p;
if(A[i].a1 != 0) { //主件+附件1
v1 = v + A[A[i].a1].v;
tempDp1 = tempDp + A[A[i].a1].v * A[A[i].a1].p;
}
if(A[i].a2 != 0){ //主件+附件2
v2 = v + A[A[i].a2].v;
tempDp2 = tempDp + A[A[i].a2].v * A[A[i].a2].p;
}
if(A[i].a1 != 0 && A[i].a2 != 0) { //主件+附件1+附件2
v3 = v + A[A[i].a1].v + A[A[i].a2].v;
tempDp3 = tempDp + A[A[i].a1].v * A[A[i].a1].p + A[A[i].a2].v * A[A[i].a2].p;
}
for(int j = 1;j <= N;j++) {
if(A[i].q > 0) { //当物品i是附件时,相当于跳过
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j];
if(j >= v && v != -1)
dp[i][j] = getMax(dp[i - 1][j], dp[i - 1][j - v] + tempDp);
if(j >= v1 && v1 != -1)
dp[i][j] = getMax(dp[i - 1][j], dp[i - 1][j - v1] + tempDp1);
if(j >= v2 && v2 != -1)
dp[i][j] = getMax(dp[i - 1][j], dp[i - 1][j - v2] + tempDp2);
if(j >= v3 && v3 != -1)
dp[i][j] = getMax(dp[i - 1][j], dp[i - 1][j - v3] + tempDp3);
}
}
}
System.out.println(dp[A.length - 1][N]);
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int m = in.nextInt();
if(m <= 0) {
System.out.println(0);
return;
}
good[] A = new good[m + 1];
int v, p, q;
for(int i = 1;i <= m;i++) {
v = in.nextInt();
p = in.nextInt();
q = in.nextInt();
A[i] = new good(v, p, q);
if(q > 0) {
if(A[q].a1 == 0)
A[q].setA1(i);
else
A[q].setA2(i);
}
}
test.printResult(N, A);
}
}
参考资料:
1.【Algothrim】 动态规划实例 (金明的预算方案 )
算法笔记_103:蓝桥杯练习 算法提高 金明的预算方案(Java)的更多相关文章
- 算法笔记_107:蓝桥杯练习 算法提高 学霸的迷宫(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要 ...
- 算法笔记_096:蓝桥杯练习 算法提高 求最大值(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大.并且要求你选定的数对的ai之和非负,bi之和非负 ...
- 算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是 ...
- 算法笔记_081:蓝桥杯练习 算法提高 矩阵乘法(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最 ...
- 算法笔记_106:蓝桥杯练习 算法提高 周期字串(Java)
目录 1 问题描述 2 解决方案 2.1 第一印象解法(80分) 2.2 借鉴网友解法(100分) 1 问题描述 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些“从前有座山,山里有座庙,庙里有 ...
- 算法笔记_102:蓝桥杯练习 算法提高 快乐司机(Java)
目录 1问题描述 2 解决方案 1 问题描述 问题描述 "嘟嘟嘟嘟嘟嘟 喇叭响 我是汽车小司机 我是小司机 我为祖国运输忙 运输忙" 这是儿歌“快乐的小司机”.话说现在当司机光 ...
- 算法笔记_099:蓝桥杯练习 算法提高 排列数(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 0.1.2三个数字的全排列有六种,按照字母序排列如下: 012.021.102.120.201.210 输入一个数n 求0~9十个数的全排 ...
- 算法笔记_105:蓝桥杯练习 算法提高 上帝造题五分钟(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 第一分钟,上帝说:要有题.于是就有了L,Y,M,C 第二分钟,LYC说:要有向量.于是就有了长度为n写满随机整数的向量 第三分钟,YUHC ...
- 算法笔记_104:蓝桥杯练习 算法提高 新建Microsoft Word文档(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 L正在出题,新建了一个word文档,想不好取什么名字,身旁一人惊问:“你出的题目叫<新建Microsoft Word文档>吗? ...
随机推荐
- CodeForces 738D Sea Battle
抽屉原理. 先统计最多有$sum$个船可以放,假设打了$sum-a$枪都没打中$a$个船中的任意一个,那么再打$1$枪必中. #pragma comment(linker, "/STACK: ...
- SVN版本控制软件
一.版本控制软件 1.为什么需要版本控制软件 问题:① 团队开发 ② 异地协作 ③ 版本回退 2.解决之道 SCM(Software Configuration Management):软件配置管理 ...
- Java使用Redis初探
Redis的相关概念不做介绍了,大家也可以先了解下Memcached,然后比较下二者的区别,就会有个整体的印象. 服务器端通常选择Linux , Redis对于linux是官方支持的,使用资料很多,需 ...
- Linux命令之useradd
useradd [选项] LOGIN(登录名) useradd –D useradd –D [选项] 创建一个新用户或更新默认新用户信息.useradd和adduser命令相同,adduser是use ...
- AGC 022 C - Remainder Game
题面在这里! 显然权值是 2^i 这种的话就是要你贪心,高位能不选就不选. 并且如果 % x 之后再去 % 一个>=x的数是没有用的,所以我们可以把操作的k看成单调递减序列. 这样的话就是一个有 ...
- 【状压DP】BZOJ2734-[HNOI2012]集合选数
已经八月份了药丸,开始肝作业并且准备高考啦!! [题目大意] <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集 ...
- JS解决URL传递参数中文乱码问题
function getUrlParam(name){ // 用该属性获取页面 URL 地址从问号 (?) 开始的 URL(查询部分) var url = window.location.search ...
- Linux限制某些用户或IP登录SSH、允许特定IP登录SSH
说明:一般要实现这种功能时,先安装VPN,然后客户端登录VPN,然后通过内网IP登录SSH. 搭建OpenVPN: 参考:http://www.cnblogs.com/EasonJim/p/83338 ...
- 微信小程序,开发者工具更新以后wxss编译错误
出现上述错误,解决方法如下: 1.在控制台输入openVendor() : 2.清除里面的wcsc wcsc.exe 3.重启开发者工具 搞定!
- 虚拟PDF打印机
doPDF虚拟打印机 doPDF 是一个免费的PDF转换器,可同时运用于商业和个人,它把自己安装为一个打印机驱动,允许从任意一个有打印输出的Windows程序中打印,还包含缩放,质量定义和页面大小定义 ...