(1)、算法原理
貪心算法總是作出在當前看來是最好的選擇,即貪心算法並不從整體最優解上加以考慮,它所作出的選擇只是在某種意義上的局部最優解。貪心算法不是對所有問題都能得到整體最優解,但對範圍相當廣的許多問題它能產生整體最優解。如圖的單源最短路徑、最小生成樹問題等。在一些情況下,即使貪心算法不能得到整體最優解,但其最終結果卻是最優解的很好近似解。
貪心算法求解的問題一般具有兩個重要性質:貪心選擇性質和最優子結構性質。所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列局部最優解的選擇,即貪心選擇來達到。這是貪心算法可行的第一個基本要素,也是貪心算法與動態規劃算法的主要區別。當一個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構性質。問題的最優子結構性質是該問題可用動態規劃算法或貪心算法求解的關鍵特徵。
(2)、解決0-1揹包算法分析
這兩類問題都具有最優子結構性質。對於0-1揹包問題,設A是能裝入容量爲c的揹包的具有最大價值的物品集合,則Aj=A-{j}是n-1個物品1,2,...,j-1,j+1,...,n可裝入容量爲c-wj的揹包的具有最大價值的物品集合。
用貪心算法求解0-1揹包問題的步驟是,首先計算每種物品單位重量的價值vi/wi;然後,將物品進行排序,依貪心選擇策略,將盡可能多的單位重量價值最高的物品裝入揹包。若將這種物品全部裝入揹包後,揹包內的物品總量未超過c,則選擇單位重量價值次高的物品並儘可能多地裝入揹包。依此策略一直進行下去,直到揹包裝滿爲止。
(3)、算法實現
import javax.swing.*;
public class Knapsack extends JFrame{
/**
* @param args
*/
public static int []flag;//保存原有的位置
final JScrollPane scrollPane = new JScrollPane();
public static JTextArea resulttextArea;
public JLabel l1 = new JLabel("最優解");
public JLabel l3 = new JLabel("所用時間");
public static JTextField t1 = new JTextField();
public static JTextField t2 = new JTextField();
final JLabel label = new JLabel();
final JLabel label_1 = new JLabel();
public Knapsack(){
this.setResizable(false);
this.setTitle("貪心算法計算0-1揹包");
this.getContentPane().setLayout(null);
this.setBounds(100, 100, 670, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
scrollPane.setBounds(190, 25, 454, 293);
getContentPane().add(scrollPane);
resulttextArea = new JTextArea();
resulttextArea.setEditable(false);
scrollPane.setViewportView(resulttextArea);
label.setHorizontalTextPosition(SwingConstants.RIGHT);
label.setHorizontalAlignment(SwingConstants.RIGHT);
label.setText("最優解:");
label.setBounds(10, 42, 66, 18);
getContentPane().add(label);
t1.setHorizontalAlignment(SwingConstants.RIGHT);
t1.setHorizontalAlignment(SwingConstants.RIGHT);
t1.setBounds(80, 42, 66, 18);
getContentPane().add(t1);
label_1.setHorizontalTextPosition(SwingConstants.RIGHT);
label_1.setHorizontalAlignment(SwingConstants.RIGHT);
label_1.setText("所用時間:");
label_1.setBounds(10, 75, 66, 18);
getContentPane().add(label_1);
t2.setHorizontalAlignment(SwingConstants.RIGHT);
// t1.setHorizontalTextPosition(SwingConstants.RIGHT);
t2.setHorizontalAlignment(SwingConstants.RIGHT);
t2.setBounds(80, 75, 66, 18);
getContentPane().add(t2);
}
//最優裝載函數(單位價值最高者先裝)
public static void Loading(int v[],int w[],int c,int n){
double []t = new double[n+1];
int x[] = new int[n];//存放物品是否放入的序列
int maxValue = 0;//最大價值
flag = new int[n];
//計算物品的單位價值
for(int i = 0; i< n; i++){
flag[i] = i;
t[i] =(double) v[i]/w[i];
}
//對物品的價值進行排序,並且將價值和重量在數組中也進行重新排序
double temp = 0;
int temp1;
int valuetemp = 0;
int weighttemp = 0;
int j;
for(int i = 0;i<n;i++){
for( j = n-1; j>i;j--){
if(t[j] > t[j-1]){
//交換單位價值
temp = t[j];
t[j] = t[j-1];
t[j-1] = temp;
//交換價值對應的位置
valuetemp = v[j];
v[j] = v[j-1];
v[j-1] = valuetemp;
//交換重量對應的位置
weighttemp = w[j];
w[j] = w[j-1];
w[j-1] = weighttemp;
temp1 = flag[j];
flag[j] = flag[j-1];
flag[j-1] = temp1;
}
}
}
//初始化裝在序列
for(int i = 0; i < n ; i++){
x[i] = 0;
}
//將物品按單位價值放入揹包中,並且確定小於等於揹包的容量
int i = 0;
for(i =0; i <n && w[i] < c;i++){
x[i] = 1;
maxValue += v[i];
c -= w[i];//容量減少
}
//如果揹包還沒放滿
int k = i;
if(c!=0){
for(k = i;k<n;k++){
if(w[k]<=c){
maxValue +=v[k];
x[k] = 1;
c -= w[k];
}
}
}
//看揹包是全部放滿還是有剩餘
System.out.print("揹包容量還剩下:"+c);
System.out.println("-------------------------------------------");
System.out.println("物品的選擇(‘0’代表沒有選擇,‘1’代表選擇)如下:");
System.out.println("-------------------------------------------");
resulttextArea.append("物品的選擇(‘0’代表沒有選擇,‘1’代表選擇)如下:/n");
//輸出最後的結果,放入揹包中的物品的序列和最大的序列
System.out.println("最大價值爲:"+maxValue);
t1.setText(""+maxValue);
for(i = 0; i < n; i++){
System.out.println("重量是:"+w[i]+" 價值是:"+v[i]+" 是否裝入揹包中:"+x[i]);
resulttextArea.append("x["+flag[i]+"]="+x[i]+"/n");
}
}
@SuppressWarnings("static-access")
public static void main(String[] args) {
final int c=1000;
final int n=50;
int[] v={220,208,198,192,180,180,
165,162,160,158,155,130,
125,122,120,118,115,110,
105,101,100,100,98,96,
95,90,88,82,80,77,
75,73,70,69,66,65,
63,60,58,56,50,30,
20,15,10,8,5,3,
1,1};
int[] w={80,82,85,70,72,70,
66,50,55,25,50,55,
40,48,50,32,22,60,
30,32,40,38,35,32,
25,28,30,22,50,30,
45,30,60,50,20,65,
20,25,30,10,20,25,
15,10,10,10,4,4,
1,1};
long start = System.currentTimeMillis();
Knapsack sack = new Knapsack();
sack.Loading(v,w,c,n);
sack.setVisible(true);
double end = System.currentTimeMillis();
t2.setText((end - start)+"ms");
}
}