贪心算法解背包问题

背包问题:0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1 <= i <= n2类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。

基本步骤:

1、算每种物品单位重量的价值Vi/Wi

2、依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包

3、若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包

4、依此策略一直地进行下去,直到背包装满为止

package cn.edu.xmu.acm.greedy;

import java.util.Arrays;
import java.util.Scanner;

/**
 * desc:贪心策略求解背包问题
 * <code>KnapSackGreedy</code>
 * @author chenwq ([email protected])
 * @version 1.0 2012/03/27
 */
public class KnapSackGreedy{
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		System.out.println("Please enter the number of objects:");
		int n = in.nextInt();
		int[] w = new int[n];
		int[] v = new int[n];
		System.out
				.println("Now,please enter the weight of these objects:");
		for (int i = 0; i < n; i++) {
			w[i] = in.nextInt();
		}
		System.out
				.println("Now,please enter the value of these objects:");
		for (int i = 0; i < n; i++) {
			v[i] = in.nextInt();
		}
		System.out
				.println("Now,please enter the capacity of the pack:");
		int c = in.nextInt();

		/**
		 * 1、计算单位价值
		 * 2、按单位重量价值 r[i]=v[i]/w[i]降序排列
		 */
		double startTime = System.currentTimeMillis();
		double[] r = new double[n];
		int[] index = new int[n];
		for (int i = 0; i < n; i++) {
			r[i] = (double) v[i] / (double) w[i];
			index[i] = i;
		}
		double temp = 0;
		for (int i = 0; i < n - 1; i++) {
			for (int j = i + 1; j < n; j++) {
				if (r[i] < r[j]) {
					temp = r[i];
					r[i] = r[j];
					r[j] = temp;
					int x = index[i];
					index[i] = index[j];
					index[j] = x;
				}
			}
		}

		/**
		 * 排序后的重量和价值分别存到w1[]和v1[]中
		 */
		int[] w1 = new int[n];
		int[] v1 = new int[n];
		for (int i = 0; i < n; i++) {
			w1[i] = w[index[i]];
			v1[i] = v[index[i]];
		}
		/**
		 * 打印按单位价值降序之后的物品和物品价值序列
		 */
		System.out.println(Arrays.toString(w1));
		System.out.println(Arrays.toString(v1));

		/**
		 * 初始化解向量x[n]
		 */
		int[] x = new int[n];
		for (int i = 0; i < n; i++) {
			x[i] = 0;
		}

		/**
		 * 按照贪心策略求解并打印解向量
		 */
		for (int i = 0; i < n; i++) {
			if (w1[i] < c) {
				x[i] = 1;
				c = c - w1[i];
			}
		}

		System.out
				.println("The solution vector is:" + Arrays.toString(x));
		/**
		 * 根据解向量求出背包中存放物品的最大价值并打印
		 */
		int maxValue = 0;
		for (int i = 0; i < n; i++) {
			if (x[i] == 1)
				maxValue += v1[i];
		}
		double endTime = System.currentTimeMillis();
		System.out
				.println("Now,the largest values of objects in the pack is:"
						+ maxValue);
		System.out.println("Basic Statements take) "
				+ (endTime - startTime) + " milliseconds!");
	}
}
背包问题拓展:物品可以部分放入背包中。详细见下述代码
package cn.edu.xmu.acm.greedy;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.text.DecimalFormat;

/*
 * Basic knapsack problem:
 *
 * We are given n objects and a knapsack.  Each object has a positive
 * weight and a positive value.  The knapsack is limited in the weight
 * that it can carry.  Fill the knapsack in a way that maximizes the
 * value of the included objects, where you are allowed to take a
 * fraction of an object.
 *
 * Author:  Timothy Rolfe
 *
 * Based on Brassard and Bratley, _Fundamentals_of_Algorithmics_,
 * pp. 202-04.
 *
 * Note:  The array "avail" is sorted several times, each with a
 *        different criterion for sorting.  Only the last time is
 * the optimal knapsack obtained (when sorted by value per weight).
 */
public class FPKnapsack {
	// Instance-scope fields
	int n; // Number of objects

	Item[] avail;// Available objects for use
	Item[] used; // objects actually used
	int nUsed;

	double maxWeight; // Weight limit of the knapsack.

	// Easy-out for IOExceptions --- throw them back to the operating system
	public static void main(String[] args) throws Exception {
		// Code for reading console from "Java in a Nutshell", p. 166
		BufferedReader console = new BufferedReader(new InputStreamReader(
				System.in));
		FPKnapsack knap = new FPKnapsack();
		String lineIn;
		String[] header = { "ranked by increasing weight",
				"ranked by decreasing value",
				"ranked by decreasing value per weight" };
		int k; // Loop variable

		System.out.print("Input file name:  ");
		if (args.length < 1)
			lineIn = console.readLine();
		else {
			lineIn = args[0];
			System.out.println(args[0]);
		}

		File f = new File(lineIn);
		FileReader fis = new FileReader(f);
		BufferedReader inp = new BufferedReader(fis);

		knap.initialize(inp);
		for (k = 0; k < 3; k++) {
			knap.fill(k);
			knap.report(header[k]);
		}
	}

	/*
	 * Data file presumption:
	 * 
	 * 1. Weight ceiling for the knapsack (one number on the line) 2. Number of
	 * candidate objects (one number on the line) ...That many number PAIRS:
	 * weight value
	 */
	void initialize(BufferedReader inp) throws Exception {
		String lineIn;

		lineIn = inp.readLine();
		maxWeight = Double.parseDouble(lineIn.trim());

		lineIn = inp.readLine();
		n = Integer.parseInt(lineIn.trim());
		// Arrays "used" and "avail" are initialized here.
		used = new Item[n];
		avail = new Item[n];

		System.out.println("\nData accepted:  n = " + n);
		System.out.println("Individual object descriptions follow.");
		for (int k = 0; k < n; k++) {
			DecimalFormat fmt0 = new DecimalFormat("0"), fmt2 = new DecimalFormat(
					"0.00");
			java.util.StringTokenizer tk = new java.util.StringTokenizer(
					inp.readLine());
			double wt = Double.parseDouble(tk.nextToken()), val = Double
					.parseDouble(tk.nextToken());

			avail[k] = new Item(wt, val);
			System.out.println("w:  " + fmt0.format(wt) + "   v:  "
					+ fmt0.format(val) + "  v/w:  " + fmt2.format(val / wt));
		}
	}

	// Fill the knapsack (i.e., move items from the heap into used[])
	void fill(int basis) {
		int k;
		Item nxt;
		double remain = maxWeight;

		nUsed = 0;

		// Put the available items into requested order
		Item.setBasis(basis);
		java.util.Arrays.sort(avail);
		for (k = 0; remain > 0 && k < avail.length; k++) {
			nxt = avail[k];
			if (nxt.w <= remain)
				nxt.x = 1;
			else
				nxt.x = remain / nxt.w;
			remain -= nxt.x * nxt.w;
			used[nUsed++] = nxt;
		}
	}

	// Show the contents --- as number pairs and fraction used.
	void report(String header) {
		DecimalFormat fmt0 = new DecimalFormat("0"), fmt2 = new DecimalFormat(
				"0.00");
		double sigVal = 0;

		System.out.println("\n" + fmt0.format(maxWeight) + " total weight "
				+ header);
		System.out.println("Knapsack contents:");
		for (int k = 0; k < nUsed; k++) {
			String lineOut = "(";

			lineOut += fmt0.format(used[k].w) + ", ";
			lineOut += fmt0.format(used[k].v) + ") --- ";
			lineOut += fmt2.format(used[k].x) + " used.";
			System.out.println(lineOut);
			sigVal += used[k].v * used[k].x;
		}
		System.out.println("Total value:   " + fmt2.format(sigVal));
	}
}

/*
 * Class of items for inclusion in the knapsack
 */
class Item implements Comparable {
	double w, // For each object, the weight of the object
			v, // For each object, the value of the object
			x; // For each object, the fraction of the object used
	double vpw; // For each object, the value-per-weight ratio
	// Basis for sorting: 0: w ascending,
	// 1: v descending
	// x: vpw descending
	static private int basis = 2;

	Item(double w, double v) {
		this.x = 0;
		this.w = w;
		this.v = v;
		this.vpw = v / w;
	}

	Item(Item c) {
		this.w = c.w;
		this.w = c.w;
		this.v = c.v;
		this.vpw = c.vpw;
	}

	public static void setBasis(int basis) {
		Item.basis = basis;
	}

	// Comparable insists on the following method signature:
	public int compareTo(Object x) {
		Item rt = (Item) x;

		// Basis for ordering is set in the static field basis
		switch (basis) { // ascending
		case 0:
			return w < rt.w ? -1 : w > rt.w ? +1 : 0;
			// descending
		case 1:
			return v < rt.v ? +1 : v > rt.v ? -1 : 0;
			// descending
		default:
			return vpw < rt.vpw ? +1 : vpw > rt.vpw ? -1 : 0;
		}
	}

}

ref:http://penguin.ewu.edu/cscd320/Topic/Strategies/Knapsack.html#fill_method

猜你喜欢

转载自irwenqiang.iteye.com/blog/1465438