貪心算法

1、定義java

什麼是貪心算法呢?所謂貪心算法是指,在對問題求解時,老是作出在當前看來最好的選擇。也就是說,不從總體最優解出發來考慮,它所作出的僅是在某種意義上的局部最優解。算法

貪心算法不是對全部問題都能獲得總體最優解,但對範圍至關普遍的許多問題都能產生總體最優解或總體最優解的近似解。數組

貪心算法的基本思路以下:app

1.創建數學模型來描述問題。函數

2.把求解的問題分紅若干個子問題。測試

3.對每一個子問題求解,獲得每一個子問題的局部最優解。spa

4.把每一個子問題的局部最優解合成爲原來問題的一個解。.net

實現該算法的過程:設計

從問題的某一初始狀態出發;blog

while 能朝給定總目標前進一步 do

求出可行解的一個解元素;

由全部解元素組合成問題的一個可行解;

2、例題分析

[揹包問題]有一個揹包,揹包容量是M=150。有7個物品,物品能夠分割成任意大小。

要求儘量讓裝入揹包中的物品總價值最大,但不能超過總容量。

物品 A  B  C  D  E  F  G

重量 35 30 60 50 40 10 25

價值 10 40 30 50 35 40 30

記得當時學算法的時候,就是這個例子,能夠說很經典。

分析:

目標函數: ∑pi最大

約束條件是裝入的物品總重量不超過揹包容量,即∑wi<=M( M=150)

(1)根據貪心的策略,每次挑選價值最大的物品裝入揹包,獲得的結果是否最優?

(2)每次挑選所佔重量最小的物品裝入是否能獲得最優解?

(3)每次選取單位重量價值最大的物品,成爲解本題的策略?

貪心算法是很常見的算法之一,這是因爲它簡單易行,構造貪心策略簡單。可是,它須要證實後才能真正運用到題目的算法中。通常來講,貪心算法的證實圍繞着整個問題的最優解必定由在貪心策略中存在的子問題的最優解得來的。

對於本例題中的3種貪心策略,都沒法成立,即沒法被證實,解釋以下:

(1)貪心策略:選取價值最大者。反例:

W=30

物品:A  B  C

重量:28 12 12

價值:30 20 20

根據策略,首先選取物品A,接下來就沒法再選取了,但是,選取B、C則更好。

(2)貪心策略:選取重量最小。它的反例與第一種策略的反例差很少。

(3)貪心策略:選取單位重量價值最大的物品。反例:

W=30

物品:A  B  C

重量:28 20 10

價值:28 20 10

根據策略,三種物品單位重量價值同樣,程序沒法依據現有策略做出判斷,若是選擇A,則答案錯誤。

值得注意的是,貪心算法並非徹底不可使用,貪心策略一旦通過證實成立後,它就是一種高效的算法。好比,求最小生成樹的Prim算法和Kruskal算法都是漂亮的貪心算法。

[均分紙牌]有N堆紙牌,編號分別爲1,2,…,n。每堆上有若干張,但紙牌總數必爲n的倍數.能夠在任一堆上取若干張紙牌,而後移動。移牌的規則爲:在編號爲1上取的紙牌,只能移到編號爲2的堆上;在編號爲n的堆上取的紙牌,只能移到編號爲n-1的堆上;其餘堆上取的紙牌,能夠移到相鄰左邊或右邊的堆上。如今要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都同樣多。例如:n=4,4堆紙牌分別爲:① 9 ② 8 ③ 17 ④ 6 移動三次能夠達到目的:從③取4張牌放到④ 再從③區3張放到②而後從②去1張放到①。

輸入輸出樣例:4

9 8 17 6

屏幕顯示:3

算法分析:設a[i]爲第I堆紙牌的張數(0<=I<=n),v爲均分後每堆紙牌的張數,s爲最小移動次數。

咱們用貪心算法,按照從左到右的順序移動紙牌。如第I堆的紙牌數不等於平均值,則移動一次(即s加1),分兩種狀況移動:

1.若a[i]>v,則將a[i]-v張從第I堆移動到第I+1堆;

2.若a[i]<v,則將v-a[i]張從第I+1堆移動到第I堆。

爲了設計的方便,咱們把這兩種狀況統一看做是將a[i]-v從第I堆移動到第I+1堆,移動後有a[i]=v; a[I+1]=a[I+1]+a[i]-v.

在從第I+1堆取出紙牌補充第I堆的過程當中可能回出現第I+1堆的紙牌小於零的狀況。

如n=3,三堆指派數爲1 2 27 ,這時v=10,爲了使第一堆爲10,要從第二堆移9張到第一堆,而第二堆只有2張能夠移,這是否是意味着剛纔使用貪心法是錯誤的呢?

咱們繼續按規則分析移牌過程,從第二堆移出9張到第一堆後,第一堆有10張,第二堆剩下-7張,在從第三堆移動17張到第二堆,恰好三堆紙牌都是10,最後結果是對的,咱們在移動過程當中,只是改變了移動的順序,而移動次數不便,所以此題使用貪心法可行的。

Java源程序:

public class Greedy {
    public static void main(String[] args) {
  int n = 0, avg =0, s = 0;
  Scanner scanner = new Scanner(System.in);
  ArrayList<Integer> array = new ArrayList<Integer>();
  System.out.println("Please input the number of heaps:");
  n = scanner.nextInt();
  System.out.println("Please input heap number:");
  for (int i = 0; i < n; i++) {
   array.add(scanner.nextInt());
  }
  for(int i = 0; i < array.size(); i ++){
   avg += array.get(i);
  }
  avg = avg/array.size();
  System.out.println(array.size());
  System.out.println(avg);
  for(int i = 0; i < array.size()-1; i ++){
   s++;
   array.set(i+1, array.get(i+1)+array.get(i)-avg);   
  }
  System.out.println("s:" + s);
 }
}

利用貪心算法解題,須要解決兩個問題:

一是問題是否適合用貪心法求解。咱們看一個找幣的例子,若是一個貨幣系統有三種幣值,面值分別爲一角、五分和一分,求最小找幣數時,能夠用貪心法求解;若是將這三種幣值改成一角一分、五分和一分,就不能使用貪心法求解。用貪心法解題很方便,但它的適用範圍很小,判斷一個問題是否適合用貪心法求解,目前尚未一個通用的方法,在信息學競賽中,須要憑我的的經驗來判斷。

二是肯定了能夠用貪心算法以後,如何選擇一個貪心標準,才能保證獲得問題的最優解。在選擇貪心標準時,咱們要對所選的貪心標準進行驗證才能使用,不要被表面上看似正確的貪心標準所迷惑,以下面的例子。

[最大整數]設有n個正整數,將它們鏈接成一排,組成一個最大的多位整數。

例如:n=3時,3個整數13,312,343,連成的最大整數爲34331213。

又如:n=4時,4個整數7,13,4,246,連成的最大整數爲7424613。

輸入:n

N個數

輸出:連成的多位數

算法分析:此題很容易想到使用貪心法,在考試時有不少同窗把整數按從大到小的順序鏈接起來,測試題目的例子也都符合,但最後測試的結果卻不全對。按這種標準,咱們很容易找到反例:12,121應該組成12121而非12112,那麼是否是相互包含的時候就從小到大呢?也不必定,如12,123就是12312而非12123,這種狀況就有不少種了。是否是此題不能用貪心法呢?

其實此題能夠用貪心法來求解,只是剛纔的標準不對,正確的標準是:先把整數轉換成字符串,而後在比較a+b和b+a,若是a+b>=b+a,就把a排在b的前面,反之則把a排在b的後面。

java源程序:

public static void main(String[] args){
  String str = "";
  ArrayList<String> array = new ArrayList<String>();
  Scanner in = new Scanner(System.in);
  System.out.println("Please input the number of data:");
  int n = in.nextInt();
  System.out.println("Please input the data:");
  while (n-- > 0) {
   array.add(in.next());   
  }
  for(int i = 0; i < array.size(); i ++)
   for(int j = i + 1; j < array.size(); j ++){
    if((array.get(i) + array.get(j)).compareTo(array.get(j) + array.get(i)) < 0){
     String temp = array.get(i);
     array.set(i, array.get(j));
     array.set(j, temp);
    }
   }  
  for(int i = 0; i < array.size(); i ++){
   str += array.get(i);
  }
  System.out.println("str=:"+str);  
 }
}

貪心算法所做的選擇能夠依賴於以往所做過的選擇,但決不依賴於未來的選擇,也不依賴於子問題的解,所以貪心算法與其餘算法相比具備必定的速度優點。若是一個問題能夠同時用幾種方法解決,貪心算法應該是最好的選擇之一。

 

徹底揹包問題
一個旅行者有一個最多能用m公斤的揹包,如今有n種物品,每件的重量分別是W1,W2,...,Wn,
每件的價值分別爲C1,C2,...,Cn.若的每種物品的件數足夠多.
求旅行者能得到的最大總價值。

 

貪心算法(又稱貪婪算法)是指,在對問題求解時,老是作出在當前看來是最好的選擇。也就是說,不從總體最優上加以考慮,他所作出的僅是在某種意義上的局部最優解。貪心算法不是對全部問題都能獲得總體最優解,但對範圍至關普遍的許多問題他能產生總體最優解或者是總體最優解的近似解。

 

 

 

貪心算法的基本思路

1.創建數學模型來描述問題。  2.把求解的問題分紅若干個子問題。  3.對每一子問題求解,獲得子問題的局部最優解。  4.把子問題的解局部最優解合成原來解問題的一個解。  實現該算法的過程:  從問題的某一初始解出發;  while 能朝給定總目標前進一步 do  求出可行解的一個解元素;  由全部解元素組合成問題的一個可行解。

 

 

  下面是一個能夠試用貪心算法解的題目,貪心解的確不錯,惋惜不是最優解。

 

 

 

[java] view plain copy

  1. /** 
  2.  * 揹包貪心法 
  3.  *  
  4.  * @author *** 
  5.  *  
  6.  */  
  7. public class Greedy {  
  8.     public static void main(String[] args) {  
  9.         Scanner in = new Scanner(System.in);  
  10.         System.out.println("Please enter the number of objects(請輸入物品的數量:):");  
  11.         int n = in.nextInt();  
  12.         int[] w = new int[n]; // 物品重量數組  
  13.         int[] v = new int[n]; // 物品價錢數組  
  14.         System.out  
  15.                 .println("Now, please enter the weight of these objects(如今請輸入這些物品的重量:)");  
  16.         for (int i = 0; i < n; i++) {  
  17.             w[i] = in.nextInt();  
  18.         }  
  19.         System.out  
  20.                 .println("Now, please enter the value of these objects(如今請輸入這些物品的價值:)");  
  21.         for (int i = 0; i < n; i++) {  
  22.             v[i] = in.nextInt();  
  23.         }  
  24.         System.out  
  25.                 .println("Now, please enter the capacity of the pack(如今請輸入揹包的容量:)");  
  26.         int c = in.nextInt();  
  27.         /** 
  28.          * 按單位重量價值r[i] = v[i] / w[i]降序排列 
  29.          *  
  30.          * ps:排序用到了選擇排序,詳情請查看選擇排序 
  31.          */  
  32.         double startTime = System.currentTimeMillis();  
  33.         double[] r = new double[n];  
  34.         int[] index = new int[n];  
  35.         for (int i = 0; i < n; i++) {  
  36.             r[i] = (double) v[i] / (double) w[i];  
  37.             index[i] = i;  
  38.         }  
  39.         double temp = 0;  
  40.         for (int i = 0; i < n - 1; i++) {  
  41.             for (int j = i + 1; j < n; j++) {  
  42.                 if (r[i] < r[j]) {  
  43.                     temp = r[i];  
  44.                     r[i] = r[j];  
  45.                     r[j] = temp;  
  46.                     int x = index[i];  
  47.                     index[i] = index[j];  
  48.                     index[j] = x;  
  49.                 }  
  50.             }  
  51.         }  
  52.         /** 
  53.          * 排序後的重量和價值分別存到w1[]和v1[]中 
  54.          */  
  55.         int[] w1 = new int[n];  
  56.         int[] v1 = new int[n];  
  57.         for (int i = 0; i < n; i++) {  
  58.             w1[i] = w[index[i]];  
  59.             v1[i] = v[index[i]];  
  60.         }  
  61.         /** 
  62.          * 初始化解向量x[n] 
  63.          */  
  64.         int[] x = new int[n];  
  65.         for (int i = 0; i < n; i++) {  
  66.             x[i] = 0;  
  67.         }  
  68.         /** 
  69.          * 求解並打印解向量 
  70.          */  
  71.         for (int i = 0; i < n; i++) {  
  72.             if (w1[i] < c) {  
  73.                 x[i] = 1;  
  74.                 c = c - w1[i];  
  75.             }  
  76.         }  
  77.         System.out  
  78.                 .println("The solution vector is(解向量是:)" + Arrays.toString(x));  
  79.         /** 
  80.          * 根據解向量求出揹包中存放物品的最大價值並打印 
  81.          */  
  82.         int maxValue = 0;  
  83.         for (int i = 0; i < n; i++) {  
  84.             if (x[i] == 1)  
  85.                 maxValue += v1[i];  
  86.         }  
  87.         double endTime = System.currentTimeMillis();  
  88.         System.out  
  89.                 .println("Now, the largest values of objects in the pack is(揹包中物品的最大價值爲:)"  
  90.                         + maxValue);  
  91.         System.out.println("Basic Statements take(基本語句用時)"  
  92.                 + (endTime - startTime) + " milliseconds!");  
  93.     }  
  94. }  
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息