0/1背包问题
描述:
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值。
输入格式:
第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。
输出格式:
第一行输出装入背包内的物体编号(末尾有空格),若没有任何物品能装入,输出: No,第二行输出背包内的物体总价值。
输入样例:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例
1 2 5
15
输入样例:
2 10
11 2
13 100
输出样例
No
0
import java.io.*;
@SuppressWarnings("all")
public class backtracking_0_1_backpack {//0-1背包问题回溯 剪枝
static int max;
private static int bound(int i,int n,int []v) {//计算剩余价值 i - n-1 的价值(找出剩余价值)
int sum = 0;
while (i < n){
sum += v[i++];
}
return sum;
}
//i 表示当前位置下标,n表示背包个数,W表示背包容量,cw表示当前重量,cv表示当前价值,v表示每个背包价值,record记录暂时最优路径,path表示最终最优路径
private static void dfs(int i,int n,int W,int cw,int cv,int []w,int []v,int []record,int []path) {
if(i == n) {//i == n,表示遍历到了叶节点 开始回溯
max = cv;
for(int j = 0;j < n;j++) {
path[j] = record[j];
}
return;
}
if(cw + w[i] <= W) {//当前重量 + 下一个要装入的 物品重量 小于背包容量(就是下一个物品可以装入的情况下) ==相当于加枝==
record[i] = 1;
dfs(i + 1,n,W,cw + w[i],cv + v[i],w,v,record,path);
}
if(cv + bound(i +1,n,v) > max) {//当不算当前价值,背包现有价值 + 剩余价值 > 当前找到最大价值,说明可能还有最优解,继续深层遍历 小于的话直接剪枝 ==相当于剪枝==
record[i] = 0;
dfs(i+1,n,W,cw,cv,w,v,record,path);
}
}
public static void main(String args[]) throws IOException{//0-1背包问题回溯 剪枝
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String []s = reader.readLine().split(" ");
int n = Integer.parseInt(s[0]);//物品个数
int W = Integer.parseInt(s[1]);//背包容量
int []w = new int[n];
int []v = new int[n];
int []record = new int[n];//临时记录那个物品被装入
int []path = new int[n];//记录那个物品被装入
for(int i = 0;i < n;i++) {
s = reader.readLine().split(" ");
w[i] = Integer.parseInt(s[0]);
v[i] = Integer.parseInt(s[1]);
}
max = -1;
dfs(0,n,W,0,0,w,v,record,path);
for(int i = 0;i < n;i++) {
if(path[i] == 1) {
System.out.print(i + 1 + " ");
}
}
if(max == 0) {//那个物品都装不下的时候
System.out.print("No");
}
System.out.print("\n" +max);
}
}