洛谷P2967题解
明显的动态规划
题目大意
\(n\) 种游戏主机,第 \(i\) 种主机的价格是 \(P_i\)。该主机有 \(G_i\) 个独占游戏。很明显,奶牛必须先买进一种游戏主机,才能买进在这种主机上运行的游戏。在每种主机中,游戏 \(j\) 的价格为 \(\mathit{GP}_j\),每头奶牛在玩了该游戏后的牛奶产量为 \(\mathit{PV}_j\)。预算为 \(V\)。请帮怎么购买,产出值的和最大。
分析
给定空间的最大价值,明显的背包啊!
本蒟蒻是不可能第一遍就打正解的。
已下是P2967的1.0版本
\(f_{i,j,v}\) 表示现在第 \(i\) 个平台,第 \(j\) 个游戏,现有预算为 \(v\) 的情况下的最大产量。
到现在为止这个方程不完整,只对后两位进行了递推,\(i\) 没有递推过,所以还要加上。
\(f_{i,0,v}\) 表示确定要用第 \(i\) 个主机
其实这个方程里面有一个隐含条件就是我们会用第 \(i\) 个主机。这样的话我们还需要考虑分给第 \(i\) 个主机多少钱。所以要再修改一下。好麻烦
已下是P2967的2.0版本
\(g_{i,v}\) 考虑前 \(i\) 个平台最大收益。
其中 \(h_{i,k}=f_{i,G_i,k-P_i }\)
程序如下:
#include<iostream>
#include<algorithm>
const int maxv = 100001;
int g[maxv], f[maxv];
int main()
{
int n, v;
std::cin >> n >> v;
while (n --> 0) {
int p, game;
std::cin >> p >> game;
for (int x = 0; x <= v; ++x)
f[x] = 0;
while (game --> 0) {
int pv, gp;
std::cin >> gp >> pv;
for (int x = v; x >= gp; x--)
f[x] = std::max(f[x], f[x-gp] + pv);
}
for (int x = v; x >= p; x--)
for (int k = x-p; k >= 0; k--)
g[x] = std::max(g[x], g[x-p-k] + f[k]);
}
std::cout << g[v];
}
跑了一下,39分。
再改!
一下是P2967的3.0正解版本
要想做好动态规划,枚举是王道。大家可以试一试,枚举一个主机,再抉择是否买第二个主机。
为了方便枚举,可以把主机的价格设为0。
假设第一个主机当中:
| 价格 | 产出 |
|---|---|
| 0 | 0 |
| 10 | 30 |
| 15 | 20 |
| 25 | 50 |
假设第二个主机价格为100元。在我们抉择是否买第二个主机的时候,可以在这个表上面修稿。如果不买,那么保存副本,如果买,就直接修改。怎么改呢?看好了!
我们把主机的价格加到表格中
| 价格 | 产出 |
|---|---|
| 100 | 0 |
| 110 | 30 |
| 115 | 20 |
| 125 | 50 |
| 这样没错吧! | |
| 再将表翻倍。 | |
| 如果有三种方案的话就翻三翻。 |
4-->8-->16-->32
那到底怎么决定买不买呢?
我们把所有的方案合并。有人会说,那会不会超时呢?
其实不会的。就算你有100000种方案,合并也只用100000次,也没什么了不起的。所以500个游戏,每个最多100000种方案,也就500000000次,不会超的。
就这样翻倍,合并,剪枝,就能比较快的决定出需不需要了。
这样讲的有些抽象,具体看看代码吧!
代码
没想到吧,只有24行!
#include<iostream>
#include<algorithm>
const int maxv = 100001;
int save[maxv], fork[maxv];
int main()
{
int n, v;
std::cin >> n >> v;
while (n --> 0) {
int p, g;
std::cin >> p >> g;
for (int x = 0; x+p <= v; ++x) // fork 在 [0, p) 之间是无效的
fork[x+p] = save[x];
while (g --> 0) {
int pv, gp;
std::cin >> gp >> pv;
for (int x = v-gp; x >= p; x--)
fork[x+gp] = std::max(fork[x+gp], fork[x] + pv);
}
for (int x = v; x >= p; x--)
save[x] = std::max(save[x], fork[x]);
}
std::cout << save[v];
}

本文来自博客园,作者:{世外第一人},转载请注明原文链接:https://www.cnblogs.com/swdyr/p/15089367.html

浙公网安备 33010602011771号