1、題目描述
2、思路分析
1、本題屬於依賴揹包問題:
有四種情況:
只取主件:f[i-1,j-a[i,0]]+a[i,0]*b[i,0]
取主件+附件1:f[i-1,j-a[i,0]-a[i,1]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]
取主件+附件2:f[i-1,j-a[i,0]-a[i,2]]+a[i,0]*b[i,0]+a[i,2]*b[i,2]
既主件+附件1+附件2:f[i-1,j-a[i,0]-a[i,1]-a[i,2]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]+a[i,2]*b[i,2]
含義:
f[i,j]表示用j元錢,買第i類物品,所得的最大價值
a[i,0]表示第i類物品主件的價格
a[i,1]表示第i類物品第1個附件的價格
a[i,2]表示第i類物品第2個附件的價格
b[i,0],b[i,1],b[i,2]分別表示主件、第1個附件和第2個附件的重要度。
需要在滿足金額money內,買到最大價值的物品。價值=價格*重要度
2、使用二維數組加狀態方程:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
//購買物品的總錢數
int N = scanner.nextInt();
//希望購買的物品的數量
int M = scanner.nextInt();
//二維數組,第i行表示第i個物品的價值,列:0表示主鍵,1表示附件1,2表示附件2
int[][] V = new int[M + 1][3];
//二維數組,第i行表示第i個物品的重要程度,列:0表示主鍵,1表示附件1,2表示附件2
int[][] P = new int[M + 1][3];
for (int i = 1; i <= M; i++) {
int v = scanner.nextInt();
int p = scanner.nextInt();
int q = scanner.nextInt();
if (q == 0) { //q=0代表是主件
V[i][0] = v;
P[i][0] = p;
} else { //q>0代表是附件,q代表附件所屬的主件編號
if (V[q][1] == 0) {
V[q][1] = v;
P[q][1] = p;
} else {
V[q][2] = v;
P[q][2] = p;
}
}
}
//下面正式開始動態規劃算法
int[][] dp = new int[M + 1][N + 1];
/**
* 1、錢夠用的時候,買不買主鍵
* 2、錢夠用的時候,買不買主鍵、附件1
* 3、錢夠用的時候,買不買主鍵、附件2
* 4、錢夠用的時候,買不買主鍵、附件1、附件2
* 5、錢不夠用的時候,只買前i-1件商品
*/
for (int i = 1; i <= M; i++) {
for (int j = 10; j <= N; j +=10) {
if (j >= V[i][0]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0]] + V[i][0] * P[i][0]);
} else if (j >= V[i][0] + V[i][1]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1]] + V[i][0] * P[i][0] + V[i][1] * P[i][1]);
} else if (j >= V[i][0] + V[i][2]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][2]] + V[i][0] * P[i][0] + V[i][2] * P[i][2]);
} else if (j >= V[i][0] + V[i][1] + V[i][2]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - V[i][0] - V[i][1] - V[i][2]] + V[i][0] * P[i][0] + V[i][1] * P[i][1] + V[i][2] * P[i][2]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
System.out.println(dp[M][N]);
}
}
}
不知道爲什麼通過率只有20%,總感覺牛客的測試數據有問題。
3、將二維數組優化爲一維數組加狀態方程:
import java.util.Scanner;
public class Main3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
//總錢數
int N = sc.nextInt();
//總物品數
int M = sc.nextInt();
//二維數組,第i行表示第i個物品的價值,列:0表示主鍵,1表示附件1,2表示附件2
int[][] V = new int[M+1][3];
//二維數組,第i行表示第i個物品的重要程度,列:0表示主鍵,1表示附件1,2表示附件2
int[][] P = new int[M+1][3];
for (int i = 1; i <= M; i++) {
int v = sc.nextInt();
int p = sc.nextInt();
int q = sc.nextInt();
if (q == 0) {
V[i][0] = v;
P[i][0] = p;
} else {
if (V[q][1]==0) {
V[q][1] = v;
P[q][1] = p;
}
else {
V[q][2] = v;
P[q][2] = p;
}
}
}
//記錄最大價值
int[] dp = new int[N+1];
/**
* 1、錢夠用的時候,買不買主鍵
* 2、錢夠用的時候,買不買主鍵、附件1
* 3、錢夠用的時候,買不買主鍵、附件2
* 4、錢夠用的時候,買不買主鍵、附件1、附件2
* 5、錢不夠用的時候,只買前i-1件商品
*/
for (int i = 1; i <= M; i++)
for (int j = N; j >= 10; j-=10) {
if (j >= V[i][0])
dp[j] = Math.max(dp[j], dp[j-V[i][0]]+V[i][0]*P[i][0]);
if (j >= V[i][0]+V[i][1])
dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]);
if (j >= V[i][0]+V[i][2])
dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][2]]+V[i][0]*P[i][0]+V[i][2]*P[i][2]);
if (j >= V[i][0]+V[i][1]+V[i][2])
dp[j] = Math.max(dp[j], dp[j-V[i][0]-V[i][1]-V[i][2]]+V[i][0]*P[i][0]+V[i][1]*P[i][1]+V[i][2]*P[i][2]);
}
System.out.println(dp[N]);
}
}
}
優化爲一維數組後,通過率爲100%,所以還是不清楚問題在哪兒,思路相同,一個對了,一個不對。