5.29翻车记录(bushi)四道各种背包问题
总体情况:
先看到第一题,很水,做完
觉得第二题稍微有些费劲,就先做三四题,
最后解决第二题
AC:T1和T4
T3:70
T4:91(题面有bug,没说是多组数据)
T1:最小乘车费用
假设某条街上每 一公里 就有一个公共汽车站,并且乘车费用如下表:
公里数 1 2 3 4 5 6 7 8 9 10
费用 12 21 31 40 49 58 69 79 90 101
而任意一辆汽车从不行驶超过 10 公里 。某人想行驶 n(1<=n<=100) 公里,假设他可以任意次换车,请你帮他找到一种乘车方案,使得总费用最小
注意: 10 公里 的费用比 1 公里 小的情况是允许的。
输入
共两行,第一行为 10 个不超过 200 的整数,依次表示行驶 1 ~ 10 公里的费用,相邻两数间用一个空格隔开;第二行为某人想要行驶的公里数。
输出
仅一行,包含一个整数,表示行使这么远所需要的最小费用。
样例:
输入:12 21 31 40 49 58 69 79 90 101
15
输出:147
很水的一维完全背包,把1-10公里看作物品,1-10为物品费用(体积),车费为价值(或者花费),求最小价值
注意要初始化2147483647
否则全是0
可选的开一下long long
#include<cstdio> #include<algorithm> using namespace std; long long sav[1005] = {}, m, dp[1000005] = {}; int main() { for(int i = 1;i <= 10;i++) { scanf("%lld", &sav[i]); } scanf("%lld", &m); for(int i = 1;i <= m;i++) { dp[i] = 2147483647; } for(int i = 1;i <= 10;i++) { for(int j = i;j <= m;j++) { dp[j] = min(dp[j],dp[j-i]+sav[i]); } } printf("%lld", dp[m]); return 0; } /* 12 21 31 40 49 58 69 79 90 101 15 */
T2:
质数和分解
洛谷P2563
先预处理出素数表
在当作一维完全背包做
结束
#include<cstdio> #include<algorithm> using namespace std; int main() { long long int n, dp[10005] = {}, jud[205] = {}, cnt = 0, sav[2005] = {}; dp[0] = 1; for(int i = 2;i <= 200;i++) { for(int j = 2;j <= 200;j++) { if(i * j <= 200) { jud[i*j] = 1; } } } for(int i = 2;i <= 200;i++) { if(jud[i] == 0) { cnt++; sav[cnt] = i; } } // printf("%d", cnt); // scanf("%lld", &n); for(int i = 1;i <= cnt;i++) { /* if(sav[i] > n) { break; }*/ for(int j = sav[i];j <= 200;j++) { dp[j] += dp[j-sav[i]]; } } // printf("%lld", dp[n]); /* for(int i = 2;i <= n;i++) { printf("%d\n", dp[i]); }*/ while(scanf("%d",&n)!=EOF) printf("%d\n",dp[n]); return 0; }
T3:
逃亡的准备:(hp厨狂喜)
在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品。现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常感谢你。
【输入格式】
第1行有2个整孰物品种数n和背包装载体积v;
第2行到i+l行每行3个整数,为第i种物品的数量m、体积w、价值s。
【输出格式】
仅包含一个整数,即为能拿到的最大的物品价值总和。
【输入样例】
2 10
3 4 3
2 2 5
【输出样例】
13
样例说明:选第一种一个,第二种两个,结果为3×1+5×2=13。
【数据规模】
对于30%的数据:1≤v≤500;1≤n≤2000;l≤m≤10;1≤w≤20;1≤s≤100;
对于lOffl6的数据:1≤v≤500;1≤n≤2000;1≤m≤5000;1≤w≤20;1≤s≤100。
多重背包板子题
但是数据量偏大
第一次写的时候把板子的循环条件写错了,以后要注意这个问题
错误的写法:(没有把判断k*sav[i] <= j放在板子里或者直接break掉,导致计算量不必要的增加)
for(int i = 1;i <= n;i++) { for(int j = v;j >= 0;j++) { for(int k = 1;k <= 第i件物品的种类;k++) { if(k * sav[i] <= j) { dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]); } } } }
正确的写法(一):直接break;(因为如果前面的k*sav[i]超过j,后面的k*sav[i]也大于j)
for(int i = 1;i <= n;i++) { for(int j = v;j >= 0;j++) { for(int k = 1;k <= 第i件物品的种类;k++) { if(k * sav[i] <= j) { dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]); } else { break; } } } }
正确的写法二:把判断写在最后一层循环里‘
for(int i = 1;i <= n;i++) { for(int j = v;j >= 0;j++) { for(int k = 1;k <= 第i件物品的种类 && k * savv[i] <= j ;k++) { dp[j] = max(dp[j],dp[j-k*savv[i]]+k*savw[i]); } } }
But,
在有写多重背包的题目中,会出现k * savv[i] > j 之后,后面的情况可能满足条件的情况。
因此,推荐第一种写法,如果出现上述特殊情况,就可以把break改成continue应对
总之,实际情况实际分析
PS:据某大佬说,判断的不同位置中有一种会导致数组下表溢出从而导致结果偏大,但我并没有发现
T3的AC代码
#include<cstdio> #include<algorithm> using namespace std; int main() { int v, n; long long dp[100005] = {}; long long sav1[20005] = {}, sav2[20005] = {}, sav3[20005] = {}; scanf("%d%d", &n, &v); for(int i = 1;i <= n;i++) { scanf("%lld%lld%lld", &sav1[i], &sav2[i], &sav3[i]); } for(int i = 1;i <= n;i++) { for(int j = v;j >= 0;j--) { for(int k = 1;k <= sav1[i];k++) { if(k * sav2[i] <= j) { dp[j] = max(dp[j],dp[j-k*sav2[i]] + sav3[i] * k); } else { break; }//卡常多过30 } } } printf("%lld", dp[v]); return 0; } /* 2 10 3 4 3 2 2 5 */
T4:暗黑游戏(csdn上有题目)
简单的二位费用多重背包
#include<cstdio> #include<algorithm> using namespace std; int main() { int n, p, r; long long savp[1005] = {}, savr[1005] = {}, savs[1005] = {}, sava[1005] = {}; long long dp[205][205] = {}; scanf("%d%d%d", &n, &p, &r); for(int i = 1;i <= n;i++) { scanf("%lld%lld%lld%lld", &savp[i], &savr[i], &savs[i], &sava[i]); } for(int i = 1;i <= n;i++) { if(savs[i] != 0) { for(int j = p;j >= 0;j--) { for(int q = r;q >= 0;q--) { for(int k = 1;k <= savs[i];k++) { if(k * savp[i] <= j && k * savr[i] <= q) { dp[j][q] = max(dp[j][q],dp[j-k*savp[i]][q-k*savr[i]] + sava[i] * k); } } } } } else { for(int j = savp[i];j <= p;j++) { for(int q = savr[i];q <= r;q++) { dp[j][q] = max(dp[j][q],dp[j-savp[i]][q-savr[i]]+sava[i]); } } } } printf("%lld", dp[p][r]); return 0; } /* 3 10 10 5 3 0 110 4 3 4 120 2 3 1 130 */
qua+