貪心算法(又稱貪婪算法Greedy):在對問題求解時,總是做出在當前看來是最好的選擇。僅是在某種意義上的局部最優解。貪心算法不是對所有問題都能得到整體最優解,但對範圍相當廣泛的許多問題他能產生整體最優解或者是整體最優解的近似解。
可用貪心算法求解的問題一般有兩個重要性質:
1、貪心選擇性質
在當前狀態下做出最好選擇,即局部最優選擇,然後再去解決做出這個選擇後產生的響應的子問題,通常以自頂向下的方式進行,以迭代的方式做出相繼的貪心選擇,每做一次貪心選擇就將所求問題簡化爲規模更小的子問題。而在動態規劃算法中,每步所做的選擇往往依賴於相關子問題的解(自底向上)。
2、最優子結構性質
當一個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構性質。
在此先提出揹包問題,與0-1揹包問題類似,所不同的是選擇物品i裝入揹包時,可以選擇i的一部分而不是全部。這樣揹包問題可以用貪心算法求解:將物品單位重量價值由高到低的順序依次放入揹包,直到揹包被裝滿。而對於0-1揹包問題,貪心選擇之所以不能得到最優解是因爲在這種情況下,它無法保證最終能將揹包裝滿,部分閒置的揹包空間使每千克揹包空間的價值降低了。
單源最短路徑貪心算法實現:
public class MaxSum { static int MAX_SIZE=6; //設頂點數爲6 public static void dijkstra(int v,float[][]a,float[]dist,int[]prev) {//v是源點,a[i][j]是邊(i,j)的權,dist[i]表示當前從源到頂點i的最短特殊路徑長度 //prev[i]記錄的是從源點到頂點i的最短路徑上i的前一個頂點 int n=dist.length-1; //n爲G圖中的頂點個數,問題的規模,0號元素未使用 if(v<1||v>n)return; //在所有點中選擇一點作爲源點v boolean []s=new boolean[n+1];//判斷點是否在集合S中,一個頂點屬於s(值爲true)當且僅當從源到該頂點的最短路徑長度已知0 for(int i=1;i<=n;i++) { dist[i]=a[v][i]; s[i]=false;//將集合s中的所有點設爲false,即dist[i]不確定是否爲最短路徑 if(dist[i]==Float.MAX_VALUE) prev[i]=0;//說明從源點v需要經過別的點才能到達i(Float.MAX_VALUE意爲大數無窮) else prev[i]=v;//有通路則讓點i的前驅指向源 } dist[v]=0;s[v]=true;//初始時s中只含有v for(int i=1;i<n;i++) { float temp=Float.MAX_VALUE; int u=v; //在剩下的點中除了沒有通路的點中找到最容易到達的,並把最容易到達的放入u中 for(int j=1;j<=n;j++) if((!s[j])&&(dist[j]<temp)) { u=j; temp=dist[j];//temp爲所有的dist[j]的最優解 } s[u]=true; //dist[u]已確定,則可將點u放入s中去 for(int j=1;j<=n;j++) if((!s[j])&&(a[u][j]<Float.MAX_VALUE)) {//源到點j通過點u的最短特殊路徑長度newdist float newdist=dist[u]+a[u][j]; if(newdist<dist[j]) {//v到j的最短路徑經過u dist[j]=newdist; prev[j]=u; } } } } public static void main(String args[]) { float a[][]=new float[MAX_SIZE][MAX_SIZE];float[]dist=new float[MAX_SIZE];int []prev=new int[MAX_SIZE]; for(int i=0;i<6;i++) for(int j=0;j<6;j++) a[i][j]=Float.MAX_VALUE; a[1][2]=10; a[1][4]=30; a[1][5]=100; a[2][3]=50; a[3][5]=10; a[4][3]=20; a[4][5]=60; int v=1;//假設從頂點1處出發 dijkstra(v,a,dist,prev); System.out.println("從1出發到2、3、4、5的最短路徑依次是:"); for(int j=2;j<6;j++) { System.out.println(dist[j]); } int z=prev[5],y=prev[z],x=prev[y]; System.out.println("從1到5最短路徑經過的點爲:"); System.out.print(x+" "+y+" "+z+" "+"5"); } }
運行結果: