题目:给你一堆app和你的手机容量,一堆app有下载容量和得到的相应金币奖励,求你想要得到最多的金币,输出这个选择路径(输入次序就是对应的编号,相同容量相同金币的app选择编号较小的下载)。
思路:
记录路径是可以,但是会被覆盖,这个覆盖是从后向前的覆盖,所以把最优的贪心到后面,进行覆盖的时候,记录下的路径是最优路径。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 10;
int dp[MAXN], vis[MAXN];
int path[MAXN][MAXN];
struct node {
int v;
int c;
int id;
}s[MAXN];
bool cmp(node x, node y) { //贪心避免路径覆盖
if(x.c != y.c) return x.c > y.c;
else if(x.v != y.v) return x.v > y.v;
return x.id > y.id;
}
int main() {
int n, p = 0;
scanf("%d", &n);
getchar();
while(1) {
scanf("%d", &s[++p].v);
s[p].id = p;
char ch = getchar();
if(ch == '\n') break;
}
for(int i = 1; i <= p; ++i)
scanf("%d", &s[i].c);
sort(s + 1, s + p + 1, cmp);
for(int i = p; i >= 1; i--) {
for(int j = n; j >= s[i].v; --j) {
if(dp[j] < dp[j - s[i].v] + s[i].c) {
dp[j] = dp[j - s[i].v] + s[i].c;
path[i][j] = 1; //记录路径
}
}
}
int tot = 0;
for(int i = 1, j = n; i <= p && j > 0; ++i) {
if(path[i][j]) {
vis[tot++] = s[i].id;
j -= s[i].v; //根据最优结果,寻找路径
}
}
sort(vis, vis + tot);
for(int i = 0; i < tot - 1; ++i) {
printf("%d ", vis[i]);
}
if(tot) printf("%d\n", vis[tot - 1]);
return 0;
}
/*
40
12 13 23 36
11 11 20 30
*/