算法:貪婪算法基礎


算法:貪婪算法基礎

理解貪心算法

說明

  貪心算法是使所做的選擇看起來都是當前最佳的,期望通過所做的局部最優選擇來產生一個全局最優解

設計貪心算法的步驟

  1.將優化問題轉換成這樣一個問題,即先做出選擇,再解決剩下的一個子問題

  2.證明原問題總是有一個最優解是貪心選擇的得到的,從而說明貪心選擇的安全。

  3.說明在做出貪心選擇后,剩下的子問題具有這樣一個性質。即如果將子問題的最優解和我們所做的貪心選擇聯合起來,可以得到一個更加負責的動態規划解。

 

剪繩子

問題描述

  給你一個長度為n的繩子,請把繩子剪成m段(m,n都是整數,且都大於1)每段繩子的長度即為K[0],K[1],K[2]...K[m]。請問K[0]*k[1]..*k[m]可能的最大乘積是多少

解決思路

  如果我們按照如下的策略剪繩子,則得到的各段繩子的長度的乘積將最大;當n>=5,我們盡可能地剪長度為3的繩子;當剩下的繩子長度為4時,把繩子剪為長度為2的繩子.

  貪心算法的核心是通過局部最優解來得到全局最優解,對於分割問題來說,要使乘積最大,該問題的貪心思想是盡可能去剪為長度為3的繩子!

Java代碼

迭代法

    public static int greedy_cut_rope_1(int n)
    {
        if(n<2)
            return 0;
        if(n==2)
            return 1;
        if(n==3)
            return 2;
        //盡可能多地去減長度為3的繩子段
        int timesOf3 = n/3;
        //當繩子最后剩下的長度為4的時候,不能再去剪去長度為3的繩子段
        if(n-timesOf3*3==1)
            timesOf3-=1;
        int timesOf2 =(n-timesOf3*3)/2;
        return (int) (Math.pow(3,timesOf3)*Math.pow(2,timesOf2));
    }

遞歸法

    public static int greedy_cut_rope(int n)
    {
        if(n==2)
            return 2;
        if(n==3)
            return 3;
        if(n<2)
            return 1;
        //int timesOf3 = n/3;
        if(n==4)
            return 4;
        return 3*greedy_cut_rope(n-3);
    }

 

背包問題

問題描述

  給定N個物品和一個容量為C的背包,物品i的重量為Wi,其價值為Vi,背包問題是如何選擇裝入背包的物品,使得裝入背包中物品的總價值最大。注意在背包問題中,可以將某種物品的一部分裝入背包中,但是不可以重復裝入。

解決思路

三種貪心思想:

  •   選擇價值最大的物品
  •   選擇重量最輕的物品
  •   選擇單位重量價值最大的物品

毫無疑問,我們當然選擇第三種咯。先把性價比最高的全部裝入,最后不足全部裝入的部分裝入。

Java實現代碼

    public static int greedy_knapSack(int[] w,int[] v,int n,int c)
    {
        //  假設物品已按單位重量降序排列
        double[] x = new double[10];
        int maxValue =0;
        int i;
        for(i=0;w[i]<c;i++)
        {
            x[i]=1; //將物品 i 裝入背包
            maxValue+=v[i];
            c=c-w[i]; // 背包剩余數量
        }
        x[i]=(double)c/w[i];    //物品i裝入一部分
        maxValue+=x[i]*v[i];
        return maxValue;    //返回背包獲得的價值
    }

 

活動選擇問題

問題描述

  假設有一個需要使某一資源的n個活動組成的集合S={a1,a2,a3...an}。該資源一次只能被一個活動占用,每個活動ai有一個開始時間Si和結束時間Fi,且0<=Si<Fi<∞。一旦被選擇后,活動ai就占據半開時間區間[Si,Fi)。如果區間[Si,Fi)與 [Sj,Fj)互不重疊,稱活動ai與aj是兼容的。活動選擇問題就是要選擇出一個由互相兼容的問題組成的最大集合

  討論下面的活動集合S,其中各活動已按結束時間的單調遞增順序進行了排序:

  

解決思路

  對於任意非空子問題Sij,設am是Sij中具有最早結束時間的活動:

    fm=min{fk:ak∈Sij}

  那么:

1.活動am在Sij的某最大兼容活動子集中被使用。

2.子問題Sim為空,所以選擇am使子問題Smj為唯一可能非空的子問題

  在解決子問題時,選擇am是一個可被合法調度、具有最早結束時間的活動。從直覺上來看,這種活動選擇方法是一種貪婪技術,他給后面剩下的待調度任務留下了盡可能多的機會。也就是說,此處的貪心選擇使得剩下的、未調度的時間最大化。

Java實現代碼

迭代貪心算法

    public static void greedy_activity_selector(int[] s,int[] f,boolean[] b)
    {
        int n = s.length-1;
        b[1]=true;
        int j=1;
        for(int i =2;i<=n;i++)
        {
            if(s[i]>f[j])
            {
                b[i]=true;
                j=i;
            }else
                b[i]=false;
        }
        for(int i=1;i<b.length;i++)
            System.out.println(b[i]);
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM