C++ 小社

貪婪演算法 Greedy Algorithm

演算法(Algorithm)是一組解決問題的明確指令或步驟,用來處理輸入資料、經過有限次數的運算,最終產生預期輸出;它像電腦的「食譜」,是電腦科學的基礎,存在於數學運算、資料處理、人工智慧等各領域,確保在有限時間和資源內達成目標,是現代科技中不可或缺的核心概念

 

- Gemini

演算法策略

貪婪法

分治法

回溯法

分支限界法

動態規劃法

演算法策略

貪婪法

分治法

回溯法

分支限界法

動態規劃法

 在每一步選擇中,都採取當前狀態下「最好」或「最優」的選擇,而不考慮長遠後的影響。

將一個複雜的問題,拆解成若干個規模較小、結構相同的子問題,分別解決後再合併結果。(例:Merge Sort)

嘗試每一種可能的路徑,當發現這條路走不通(不符合條件)時,就退回上一步,改走別條路。

它會維護一個「界限」(Bound),在搜尋過程中,如果發現某個分支最好的可能結果也比不上目前已找到的解,就直接捨棄該分支。

 當子問題會「重複出現」時,我們會將子問題的結果存起來(查表),下次遇到相同的子問題直接拿來用,避免重複計算。

貪婪演算法就是一個貪婪的演算法(?)

貪婪的定義:

在每一步尋找最佳解,以形成全域的最佳解

Step 1 定義貪婪準則

Step 2 不斷重複貪婪準則,直到解決問題為止

Knapsack problem

【背包問題】

有一個背包可以背特定重量的東西,

有一堆東西,

每個東西有自己的重量和價值。

要選哪些東西裝進背包,才能最大化所背的價值?

Knapsack problem

物品編號 重量 價值
0 22 19
1 10 9
2 9 9
3 7 6

背包可承受重量 = 25

Fractional Knapsack problem

【可以分割的背包問題】

拿一個東西不一定要整個都拿,可以拿一部分就好。

Fractional Knapsack problem

如果從輕的開始拿 : 6 + 9 + 9*(9/10) =23.1 

物品編號 重量 價值
0 22 19
1 10 9
2 9 9
3 7 6

Fractional Knapsack problem

如果從貴的開始拿 :19 + 9*(3/10) = 21.7

物品編號 重量 價值
0 22 19
1 10 9
2 9 9
3 7 6

Fractional Knapsack problem

好像怪怪的?

應該把價錢和重量都考量進去

Fractional Knapsack problem

物品編號 重量 價值 價值 / 重量
0 22 19 0.8636
1 10 9 0.9
2 9 9 1
3 7 6 0.857

9+9+19*(6/22) = 23.18

貪婪:每一步都選擇「性價比最高」的選項

#include<iostream>
#include<algorithm>
using namespace std;
struct obj{
  int w;
  int v;
  double vw; 
};
bool cmp(obj a,obj b){
  return (a.vw>b.vw);
}
int main(){
  int n,k,ktmp;
  double totalv;
  obj ob[101];
  while(cin>>n){
    for(int i=0;i<n;i++){
      cin >> ob[i].w >> ob[i].v;
      ob[i].vw=(double)ob[i].v/ob[i].w;
    }
    cin >> k;
    ktmp=k;
    sort(ob,ob+n,cmp);
    for(int i=0;i<n;i++){
      if (ob[i].w<=ktmp) {
        totalv+=ob[i].v;
        ktmp-=ob[i].w;
      }else{
        totalv+=(double)ob[i].vw*ktmp;
        break;
      }
    }
    cout << totalv << endl;
  }
}

最多有幾個工作可以執行

有 n 個工作可以執行,給定每個工作的開始時間與結束時間,時間從 0 開始,開始與結束時間都是整數。

 

只有一台機器可以執行,每次只能執行一個工作,且工作開始做就需要做完。

 

不考慮切換所需時間,請計算執行完後最多有幾個工作被完成?

貪婪準則是將結束時間最早的工作先做,讓機器可以空下來準備做其他工作。先將n個工作以結束時間較早的工作排在前面,利用此原則排序好n個工作。

#include<iostream>
#include<algorithm>
using namespace std;
struct job{
  int s;
  int e; 
};
bool cmp(job a,job b){
  return a.e<b.e;
}
int main(){
  int n,now,ans;
  job jb[101];
  while(cin>>n){
    for(int i=0;i<n;i++){
      cin >> jb[i].s>>jb[i].e; 
    }
    sort(jb,jb+n,cmp);
    ans=0;
    now=-1;
    for(int i=0;i<n;i++){
      if (now<=jb[i].s) {
        ans++;
        now=jb[i].e;
      }
    }
    cout << ans << endl;
  }
 }

最多有幾台機器一起運作

有n個工作可以執行,給定每個工作的開始時間與結束時間,工作時間可能重疊。

 

時間從0開始,開始與結束時間都是整數,有n台機器可以執行,每台機器同時間只可以執行一個工作,工作可以到每台機器去執行,且工作開始做就需要做完,機器執行中不能跳到另一個工作,可以一結束就馬上接著執行另一個工作,機器更換工作很快,可以不考慮切換所需時間,執行完後最少需要幾台機器才能完成所有工作?

最多有幾台機器一起運作

貪婪準則是先將n個工作以開始時間最早的工作排在前面,若開始時間相同就以最早結束的工作排在前面進行排序,將排序好的工作,由最前面依序取出每個工作,優先分配到目前已經執行完畢或沒有工作可以執行的機器,若全部機器都有工作正在執行就需要啟用新的機器。需使用陣列m,紀錄每個機器執行目前工作完成後的時間,才能判斷機器是否有空可以執行下一個工作,還是要啟動新的機器。

#include<iostream>
#include<algorithm>
using namespace std;
struct job{
  int s;
  int e; 
};
bool cmp(job a,job b){
  if (a.s==b.s) return a.e<b.e;
  return a.s<b.s;
}
int main(){
  int n,ans,m[101];
  job jb[101];
  while(cin>>n){
    for(int i=0;i<n;i++){
      cin >> jb[i].s>>jb[i].e; 
    }
    sort(jb,jb+n,cmp);
    ans=1;
    m[0]=jb[0].e;
    for(int i=1;i<n;i++){
      bool found=false;
      for(int j=0;j<ans;j++){
        if (m[j]<=jb[i].s){
          m[j]=jb[i].e;
          found=true;
          break;
        }
      }
      if (!found){
        m[ans]=jb[i].e;
        ans++;
      }
    }
    cout << ans << endl;
  }
}

C++ 小社 貪婪

By Suzy Huang

C++ 小社 貪婪

  • 65