9、實驗八貪心算法解決揹包問題
實驗內容
使用重量貪心、價值貪心和價值密度貪心三種貪心準則,求解揹包問題。
本次實驗,自行設計輸入提示、輸入數據形式、結果輸出樣式,需要認真思考,都需要用戶輸入哪些基本數據、最終需要顯示哪些結果信息,才能使用戶根據結果提示,正確完成物品的全部存放過程。(本次實驗報告批改時,這些都作爲採分點)
解題思路
重量貪心:從剩下的物品中,選出可裝入揹包的重量最小的物品。
價值貪心:從剩下的物品中,選出可裝入揹包的價值最大的物品。
價值密度貪心:從剩下的物品中,選出可裝入揹包的值最大的物品。
以價值密度貪心作爲例子,其他兩種類似:
1、計算每種物品單位的價值
2、將盡可能多的單位重量價值最高的物品裝入揹包
3、若將這種物品全部裝入揹包後,揹包內物品的總重量未超過揹包的容量C,則選擇單位重量價值次高的物品並儘可能多地裝入。
源代碼
package h貪心算法解決揹包問題;
import java.util.Scanner;
/**
* @author Draco
* @see 貪心準則:價值貪心
* @version 1.0
* @date-time 2020-06-08 - 下午12:31:11
*/
public class Value {
public static Scanner scanner = new Scanner(System.in);
public static int n;// 物品個數
public static float C;// 揹包容量
public static float[] weight;// 重量數組
public static float[] value;// 價值數組
// 拷貝的目的是,在後面對重量數組和價值數組進行了排序,打亂了原來的數組順序,故先拷貝出來一份。
public static float[] v;// 拷貝一份價值數組
public static float[] w;// 拷貝一份重量數組
public static float[] add;// 放入的比例數組
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.print("請輸入物品的個數:");
n = scanner.nextInt();
weight = new float[n];
value = new float[n];
v = new float[n];
w = new float[n];
System.out.print("請輸入揹包的容量:");
C = scanner.nextFloat();
System.out.println("請輸入物品的重量和價值:");
for (int i = 0; i < n; i++) {
weight[i] = scanner.nextFloat();
value[i] = scanner.nextFloat();
// 進行拷貝
v[i] = value[i];
w[i] = weight[i];
}
addBag();
float total = totalValue();
System.out.println("揹包的總價值爲:" + total);
}
/**
* @see 計算總價值
* @return 返回總價值
*/
public static float totalValue() {
float total = 0;
for (int i = 0; i < n; i++) {
total += add[i] * value[i];
}
return total;
}
/**
* @see 計算物品放入的比例,放入到add數組中
*/
public static void addBag() {
add = new float[n];
// 給價值數組進行排序,價值大的在前面
int index[] = Arraysort(value);// 對value進行了排序
for (int i = 0; i < n; i++) {
if (w[index[i]] <= C) {
// 加入揹包中
add[index[i]] = 1;
C = C - w[index[i]];
} else {
// 按比例加入揹包中
add[index[i]] = C / w[index[i]];
}
}
System.out.print("放入重量比例:");
for (float i : add) {
System.out.print("\t" + i);
}
System.out.println();
System.out.print("單個物品價值:");
for (float i : value) {
System.out.print("\t" + i);
}
System.out.println();
}
/**
* @see 將傳進來的數組進行排序,小的在前面
* @param arr
* @return 返回原來數組的下標
*/
public static int[] Arraysort(float[] arr) {
float temp;
int index;
int k = arr.length;
int[] Index = new int[k];
for (int i = 0; i < k; i++) {
Index[i] = i;
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] < arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
index = Index[j];
Index[j] = Index[j + 1];
Index[j + 1] = index;
}
}
}
return Index;
}
}
package h貪心算法解決揹包問題;
import java.util.Scanner;
/**
* @author Draco
* @see 貪心準則:重量貪心
* @version 1.0
* @date-time 2020-06-08 - 下午12:30:28
*/
public class Weight {
public static Scanner scanner = new Scanner(System.in);
public static int n;// 物品個數
public static float C;// 揹包容量
public static float[] weight;// 重量數組
public static float[] value;// 價值數組
// 拷貝的目的是,在後面對重量數組和價值數組進行了排序,打亂了原來的數組順序,故先拷貝出來一份。
public static float[] v;// 拷貝一份價值數組
public static float[] w;// 拷貝一份重量數組
public static float[] add;// 放入的比例數組
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.print("請輸入物品的個數:");
n = scanner.nextInt();
weight = new float[n];
value = new float[n];
v = new float[n];
w = new float[n];
System.out.print("請輸入揹包的容量:");
C = scanner.nextFloat();
System.out.println("請輸入物品的重量和價值:");
for (int i = 0; i < n; i++) {
weight[i] = scanner.nextFloat();
value[i] = scanner.nextFloat();
// 進行拷貝
v[i] = value[i];
w[i] = weight[i];
}
addBag();
float total = totalValue();
System.out.println("揹包的總價值爲:" + total);
}
/**
* @see 計算總價值
* @return 返回總價值
*/
public static float totalValue() {
float total = 0;
for (int i = 0; i < n; i++) {
total += add[i] * value[i];
}
return total;
}
/**
* @see 計算物品放入的比例,放入到add數組中
*/
public static void addBag() {
add = new float[n];
// 給重量數組進行排序,重量小的在前面
int index[] = Arraysort(weight);// 對weight進行了排序
for (int i = 0; i < n; i++) {
if (w[index[i]] <= C) {
// 加入揹包中
add[index[i]] = 1;
C = C - w[index[i]];
} else {
// 按比例加入揹包中
add[index[i]] = C / w[index[i]];
}
}
System.out.print("放入重量比例:");
for (float i : add) {
System.out.print(i + "\t");
}
System.out.println();
System.out.print("單個物品價值:");
for (float i : value) {
System.out.print(i + "\t");
}
System.out.println();
}
/**
* @see 將傳進來的數組進行排序,小的在前面
* @param arr
* @return 返回原來數組的下標
*/
public static int[] Arraysort(float[] arr) {
float temp;
int index;
int k = arr.length;
int[] Index = new int[k];
for (int i = 0; i < k; i++) {
Index[i] = i;
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
index = Index[j];
Index[j] = Index[j + 1];
Index[j + 1] = index;
}
}
}
return Index;
}
}
package h貪心算法解決揹包問題;
import java.util.Scanner;
/**
* @author Draco
* @see 貪心準則:價值密度貪心
* @version 1.0
* @date-time 2020-06-08 - 上午11:02:59
*/
public class Density {
public static float C1 = 0;// 總價值
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
System.out.print("請輸入物品的個數:");
int n = scanner.nextInt();
System.out.print("請輸入揹包的容量:");
float C = scanner.nextFloat();
System.out.println("請輸入物品的重量和價值:");
float[] wi = new float[n + 2];
float[] vi = new float[n + 2];
float[] x = new float[n + 2];
float[] v2 = new float[n + 1];
float[] w2 = new float[n + 1];
for (int i = 1; i <= n; i++) {
wi[i] = scanner.nextFloat();
vi[i] = scanner.nextFloat();
v2[i] = vi[i];
w2[i] = wi[i];
}
Density test = new Density();
test.Knapsack(n, C, vi, wi, x, v2, w2);
System.out.println();
System.out.print("單個物品價值:");
for (int i = 1; i <= n; i++) {
System.out.print("\t" + v2[i]);
}
System.out.println();
System.out.println("揹包的總價值爲:" + C1);
}
/**
* @see 將物品按價值比從大到小排放在數組
* @param n 物品個數
* @param v 價值數組
* @param w 重量數組
*/
void Sort(int n, float[] v, float w[]) {
float temp1;
float temp2;
for (int i = 1; i <= n; i++) {
for (int s = 1; s <= i; s++) {
if (v[i] / w[i] > v[s] / w[s]) {
temp1 = v[s];
temp2 = w[s];
v[s] = v[i];
w[s] = w[i];
v[i] = temp1;
w[i] = temp2;
}
}
}
}
void Knapsack(int n, float W, float v[], float w[], float x[], float v2[], float w2[]) {
Density a = new Density();
a.Sort(n, v, w);
int i;
for (i = 1; i <= n; i++)
x[i] = 0;
float c = 0;
for (i = 1; i <= n; i++) {
if (w[i] > W)
break;// 如果物品的重量大於揹包剩餘容量,停止放入整個物品
for (int t = 1; t <= n; t++) {
if (w[i] == w2[t] && v[i] == v2[t])// 將放入了的物品標記爲1
x[t] = 1;
}
W -= w[i];
c += v[i];
}
if (i <= n) {
for (int q = 1; q <= n; q++) {
if (w[i] == w2[q] && v[i] == v2[q]) {
x[q] = W / w[i];// 放入部分物品記錄放入的比例
c += x[q] * v[i];
}
}
}
System.out.print("放入重量比例:");
for (int k = 1; k <= n; k++) {
System.out.print("\t" + x[k]);
}
C1 = c;
}
}