JAVA回溯法求0-1背包

题目描述

有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。

输入

多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。

输出

背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2…j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。

样例输入 Copy

5
6 3 6 5 4
2 2 4 6 5
8

样例输出 Copy

15 1 2 3

package book;

import java.util.Scanner;

public class backtrace01 {
static int n;//物品数量
static int v[];//价值
static int w[];//重量
static int cc,bc;//当前背包重量和当前最佳背重量
static int Maxc,Cmax;//背包最大容量,背包剩余容量
static int Cway[],Fway[];//当前装物品的方案,最佳装物品的方案
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();//物品数量
		v=new int[n];
		w=new int[n];
		Cway=new int[n];
		Fway=new int[n];
		cc=bc=0;
		for(int i=0;i<n;i++) {
			v[i]=sc.nextInt();
		}
		for(int i=0;i<n;i++) {
			w[i]=sc.nextInt();
		}
		Maxc=sc.nextInt();//最大背包容量
		Cmax=Maxc;
		backtrace(0);
		print();
		

	}
	private static void print() {
	System.out.print(bc+" ");
	for(int i=0;i<n;i++) {
		if(Fway[i]==1) {
			System.out.print(i+1+" ");
		}
	}
	
		
	}
	private static void backtrace(int i) {
		if(i>n-1) {
			if(cc>bc) {
				bc=cc;
				for(int k=0;k<n;k++) {
					Fway[k]=Cway[k];
				}
			}
		}else {
		     if(Cmax>=w[i]) {
		    	 Cmax-=w[i];
		    	 cc+=v[i];
		    	 Cway[i]=1;
		    	 backtrace(i+1);
		    	 Cmax+=w[i];
		    	 cc-=v[i];
		    	 Cway[i]=0;
		    	 
		     }
		     if(check(i+1)+cc>bc) {
		    	 backtrace(i+1);
		     }
			
			
			
		}
		
	}
	private static int check(int i) {
		int count=0;
		for(int j=i;j<n;j++) {
			count+=v[i];
		}
		return count;
	}

}

第二篇过程详解

package lianxi5;

import java.util.Scanner;


public class Main56{
	static int num, maxc,cmax,currentbest,best;
	static int v[],w[],
	currentway[],Fway[];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			num=sc.nextInt();//物品数量
			v=new int[num+1];//价值背包
			w=new int[num+1];//重量背包
			currentway=new int[num+1];//当前背包
			Fway=new int[num+1];//最好背包
			for(int i=1;i<=num;i++) {
				v[i]=sc.nextInt();//依次放价值
			}
			for(int i=1;i<=num;i++) {
				w[i]=sc.nextInt();//依次放价值
			}
			maxc=sc.nextInt();//最大背包容量
			cmax=maxc;//背包容量赋值
			currentbest=0;//当前最佳
			best=0;//最终最佳
			backtrack(1);
			print();
		}
	}
	private static void print() {
		System.out.print(best+" ");
		for (int i=1;i<=num ;i++) {
			if(Fway[i]==1)
				System.out.print(i+" ");
		}
		
	}
	private static void backtrack(int i) {
	
		if(i>num){//如果放到最後一個物品,那一定是最佳方案
			if(currentbest>best){//判斷當前的最佳最佳和之前的最佳方案
			best=currentbest;//交換
			for (int j = 1; j <=num; j++) {
				Fway[j]=currentway[j];//交換
			  }
			}

		}
		else {//第一种选
		if(maxc>=w[i]){//当前剩余容量
			maxc-=w[i];//更新剩余容量
			currentbest+=v[i];//更新当前最佳容量
			currentway[i]=1;//将选中的物品标志更改为
			backtrack(i+1);//继续回溯
			maxc+=w[i];
			currentbest-=v[i];
			currentway[i]=0;
		}//第二种不选
		if(check(i+1)+currentbest>best)
			backtrack(i+1);//当前物品大于剩余容量,但是除了他不放,把之后的物品都放入还可以得到一个优于现有解
		//当前物品不选继续递归下一个
	    }
	}
	private static int check(int k) {
		int bound=0;
		for(int j=k;j<=num;j++)
			bound+=v[j];
		return bound;
	}
}
原文地址:https://www.cnblogs.com/hzcya1995/p/13309590.html