貪心演算法:從多個方面深入探究

一、什麼是貪心演算法

貪心演算法是一種常見的演算法思想,在很多問題中都有應用。貪心演算法是一種直觀而且簡單的演算法,通過每一步選擇中都採取最優的選擇來達到整體最優的解。

貪心演算法思路比較單一,每次選擇都是當前狀態下的最優選擇,因此複雜度通常較低。但是,貪心演算法的正確性較難證明,很多問題並不是貪心選擇一定是最優解,需要對每個問題進行分析。

貪心演算法用於解決那些具有最有子結構性質的問題,即問題可以分解為更小的子問題,每個子問題的最優解可以遞推得到整個問題的最優解。

二、貪心演算法的基本思想

貪心演算法要求在每一步選擇中都採取最優的選擇,而得到問題的最優解。

貪心演算法通常分為兩個階段:

  • 建立數學模型來描述問題,找到最優解的性質;
  • 利用貪心思想,每一步都做出局部最優的選擇,從而達到全局最優。

貪心演算法的核心是在每一步選擇中都採取最優的選擇,但此時必須具有無後效性。即某個狀態以及之前的狀態所做的選擇,不會影響以後的狀態。只需要考慮當前狀態下的最優解,和之前的選擇無關。

三、貪心演算法的應用

1、背包問題

背包問題是一類經典的貪心演算法問題,通常有兩種類型:0/1背包問題和完全背包問題。

對於0/1背包問題,每個物品只能選一次。物品有兩個限制,一個是總重量不能超過背包的最大承重,另一個是每個物品的重量和價值都不相同。貪心策略是每次選取價值比較高的物品放進背包,直到不能再加為止。這樣可以獲得比較好的解,但不一定是最優解。

完全背包問題中,每個物品可以選擇多次放入背包中。這種問題可以轉換為一個貪心問題,每次選取價值比較高的物品,直到背包無法再放下為止。

#include
using namespace std;

struct node{
    int w;//重量
    int v;//價值
};

int cmp(node a, node b){
    return a.v > b.v;//按價值從大到小排序
}

double knapsack(node a[], int n, int m){
    double ans = 0.0;
    int i;
    sort(a, a+n, cmp);
    for(i=0; i m) break;
        else{
            ans += a[i].v;//先選價值最大的物品
            m -= a[i].w;
        }
    }
    if(i >n>>m;//n個物品,m為背包容量
    int i;
    node a[n];
    for(i=0; i>a[i].w>>a[i].v;
    }
    printf("%.2lf", knapsack(a, n, m));
    return 0;
}

2、活動選擇問題

活動選擇問題是一種常見的貪心演算法問題,也被稱為區間調度問題。該問題要求安排一個學生參加儘可能多的互不衝突的活動,以達到時間上最合理的目的。

具體實現方法是按照每個活動的結束時間從小到大排序,然後依次選擇最早結束的活動,直到無法再加入為止。

#include
#include
using namespace std;

struct activity{
    int start;//開始時間
    int end;//結束時間
};

bool cmp(activity a, activity b){
    return a.end>n;
    activity a[n];
    int i;
    for(i=0; i>a[i].start;
        cin>>a[i].end;
    }
    sort(a, a+n, cmp);//按結束時間從小到大排序
    int cnt=1;
    int last=a[0].end;
    for(i=1; i=last){
            cnt++;//計算可安排的活動數目
            last=a[i].end;
        }
    }
    cout<<cnt;
    return 0;
}

3、霍夫曼編碼

霍夫曼編碼是一種使用較廣泛的編碼技術,主要應用於數據壓縮。

在進行編碼時,通常按照每個字元的出現概率從小到大排序。然後使用貪心演算法構建一個霍夫曼樹,來得到一組字元的編碼方式,保證編碼長度的最小化和解碼的唯一性。

#include
#include
#include
#include
using namespace std;

struct node{
    int data;//節點權值
    node* left;//左子節點指針
    node* right;//右子節點指針
};

struct cmp{
    bool operator () (node *a, node *b){
        return a->data > b->data;
    }
};

string code[500];
node* root;

void preorder(node *p, string str){
    if(!p) return;
    if(!p->left && !p->right){
        code[p->data] = str;
    }
    preorder(p->left, str+'0');
    preorder(p->right, str+'1');
}

void build(char a[], int b[], int n){
    int i;
    node *left, *right;
    priority_queue<node*, vector, cmp> q;
    for(i=0; idata = a[i];
        p->left = NULL;
        p->right = NULL;
        q.push(p);
    }
    while(q.size()>1){
        left = q.top();
        q.pop();
        right = q.top();
        q.pop();
        node *p = new node;
        p->data = 0;
        p->left = left;
        p->right = right;
        p->data = left->data + right->data;
        q.push(p);//構建霍夫曼樹
    }
    root = q.top();
    preorder(root, "");
}

int main(){
    char a[1000];//只考慮ASCII碼部分,總共只有256個字元
    int b[1000];
    memset(code, 0, sizeof(code));//所有編碼初始化為0
    int n, i;
    cin>>n;
    for(i=0; i>a[i]>>b[i];
    }
    build(a, b, n);//構建霍夫曼樹
    for(i=0; i<256; i++){
        if(code[i]!=""){
            cout<<(char)i<<" "<<code[i]<<endl;//輸出字元對應的編碼
        }
    }
    return 0;
}

4、最小生成樹

最小生成樹是一個圖的子集,可以與所有頂點相連而不形成環,並且權值之和最小。

貪心演算法應用非常廣泛,其中包括基於貪心策略的Prim演算法和Kruskal演算法。Prim演算法是在新生成的最小生成樹中加入一個頂點,然後找到與其相鄰的最短邊,將其加入最小生成樹。Kruskal演算法則是將所有邊按照權值從小到大排序,依次加入最小生成樹中,同時保證之前加入的邊不會形成環。

#include
#include
using namespace std;

const int maxn = 1000;
const int inf = 0x3f3f3f;

int eg[maxn][maxn];
int vis[maxn];
int ans;

int prim(int n){
    int i, j, minn;
    vis[1] = 1;//從1開始遍歷
    for(i=1; i<n; i++){
        minn = inf;
        int u = -1;
        for(j=1; j<=n; j++){
            if(vis[j]){
                for(int k=1; k<=n; k++){
                    if(!vis[k] && eg[j][k] >n>>m;//n個點,m條邊
    int i, j, x, y, w;
    for(i=1; i<=n; i++){
        for(j=1; j<n; j++){
            eg[i][j] = inf;
        }
    }
    for(i=0; i>x>>y>>w;//x和y之間的邊權值為w
        eg[x][y] = eg[y][x] = w;
    }
    ans = 0;
    cout<<prim(n);//輸出最小生成樹的權值
    return 0;
}

四、貪心演算法的局限性

儘管貪心演算法在許多問題中應用廣泛,但並不是所有問題都適用於貪心思想。貪心演算法求得的最優解可能並不是全局最優解。

有一些問題中,每個局部最優解可以得到全局最優。比如霍夫曼編碼,貪心演算法比較適用。但是對於一些問題,貪心策略可能無法達到全局最優解。比如旅行商問題,這是一個NP問題,通過貪心策略得到的最優解與全局最優解可能存在很大的誤差。

因此,在處理這些問題時,需要對每個問題進行判斷和分析。同時,可以通過優化貪心策略,得到比較好的局部最優解,來逐步逼近全局最優解。真正的全局最優解通常需要通過枚舉或動態規劃等方法得到。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/248712.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 13:29
下一篇 2024-12-12 13:29

相關推薦

  • 蝴蝶優化演算法Python版

    蝴蝶優化演算法是一種基於仿生學的優化演算法,模仿自然界中的蝴蝶進行搜索。它可以應用於多個領域的優化問題,包括數學優化、工程問題、機器學習等。本文將從多個方面對蝴蝶優化演算法Python版…

    編程 2025-04-29
  • 為什麼Python不能編譯?——從多個方面淺析原因和解決方法

    Python作為很多開發人員、數據科學家和計算機學習者的首選編程語言之一,受到了廣泛關注和應用。但與之伴隨的問題之一是Python不能編譯,這給基於編譯的開發和部署方式帶來不少麻煩…

    編程 2025-04-29
  • Python實現爬樓梯演算法

    本文介紹使用Python實現爬樓梯演算法,該演算法用於計算一個人爬n級樓梯有多少種不同的方法。 有一樓梯,小明可以一次走一步、兩步或三步。請問小明爬上第 n 級樓梯有多少種不同的爬樓梯…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • AES加密解密演算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密演算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES演算法,並對實現過程進…

    編程 2025-04-29
  • Python合併多個相同表頭文件

    對於需要合併多個相同表頭文件的情況,我們可以使用Python來實現快速的合併。 一、讀取CSV文件 使用Python中的csv庫讀取CSV文件。 import csv with o…

    編程 2025-04-29
  • Harris角點檢測演算法原理與實現

    本文將從多個方面對Harris角點檢測演算法進行詳細的闡述,包括演算法原理、實現步驟、代碼實現等。 一、Harris角點檢測演算法原理 Harris角點檢測演算法是一種經典的計算機視覺演算法…

    編程 2025-04-29
  • 數據結構與演算法基礎青島大學PPT解析

    本文將從多個方面對數據結構與演算法基礎青島大學PPT進行詳細的闡述,包括數據類型、集合類型、排序演算法、字元串匹配和動態規劃等內容。通過對這些內容的解析,讀者可以更好地了解數據結構與算…

    編程 2025-04-29
  • 瘦臉演算法 Python 原理與實現

    本文將從多個方面詳細闡述瘦臉演算法 Python 實現的原理和方法,包括該演算法的意義、流程、代碼實現、優化等內容。 一、演算法意義 隨著科技的發展,瘦臉演算法已經成為了人們修圖中不可缺少…

    編程 2025-04-29
  • 從多個方面用法介紹yes,but let me review and configure level of access

    yes,but let me review and configure level of access是指在授權過程中,需要進行確認和配置級別控制的全能編程開發工程師。 一、授權確…

    編程 2025-04-29

發表回復

登錄後才能評論