题解:暗黑破坏神
目录
- 题目
- 【问题描述】
- 【输入】
- 【输出】
- 【输入输出样例】
- 解析
- 法一:
- 法二:
- 代码:
题目
【问题描述】
游戏的主人公有n 个魔法,每个魔法分为若干个等级,第i 个魔法有p[i]个等级,每个魔法的每个等级都有一个效果值,一个j 级的i 种魔法的效果值为w[i,j],魔法升一级需要一本相应的魔法书,购买魔法书需要金币,第i 个魔法的魔法书价格为c[i],而小x 只有m 个金币。
你的任务就是帮助小x 决定如何购买魔法书才能使所有魔法的效果值之和最大,开始的时候所有魔法都是0 级,效果值为0。
【输入】
第一行用空格隔开的两个正整数n 和m,表示魔法的总数和金币的数量。
以下n 行,描述n 个魔法,第i+1 行描述第i 个魔法,均为整数。格式如下:
C[i] p[i] w[i,1] w[i,2] w[i,3]…w[i,p[i]]。
【输出】
输出只有一行一个整数,表示最大的魔法效果总和。
【输入输出样例】
diablo.in
3 10
1 3 1 2 2
2 3 2 4 6
3 3 2 1 10
diablo.out
11
解析
这道题在正常的dp上没有任何困难,主要的问题在于输出路径:
法一:
for (int i = m; i >= 1; i--)
if (maxn <= f[i]) {
maxn = f[i];
j = i;
}
for (int i = n; i >= 1; i--) {
road[i] = d[i][j];
j-=road[i] * c[i];
}
for (int i = 1; i <= n; i++)
printf("%d\n",road[i]);
法二:
递归输出
void print(int k,int left) {
if(k == 0) return;
print(k - 1,left - num[k][left] * c[k]);
printf("%d\n" ,num[k][left]);
}
代码:
#include
using namespace std;
int n,m,tot,c[1010],v[50010],w[50010],p[1010][500],f[52000],d[1010][510],road[1010];
int num[1001][1001];
void print(int k,int left) {
if(k == 0) return;
print(k - 1,left - num[k][left] * c[k]);
printf("%d\n" ,num[k][left]);
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) {
scanf("%d%d",&c[i],&p[i][0]);
for (int j = 1; j <= p[i][0]; j++) {
int value;
scanf("%d",&value);
w[++tot] = j * c[i];
v[tot] = value;
p[i][j] = tot;
}
}
for (int i = 1; i <= n; i++) {
for (int j = m; j >= 0; j--) {
for (int k = 1; k <= p[i][0]; k++) {
if (j - w[p[i][k]] >= 0) {
if (f[j] < f[j - w[p[i][k]]] + v[p[i][k]]) {
f[j] = f[j - w[p[i][k]]] + v[p[i][k]];
d[i][j] = k;
num[i][j] = k;
}
}
}
}
}
printf("%d\n",f[m]);
int j;
int maxn = 0;
int pl = m;
while(f[pl] == f[pl - 1]) pl--;
print(n,pl);
return 0;
}
/*
3 10
1 3 1 2 2
2 3 2 4 6
3 3 2 1 10
11
1
0
3
*/