实验要求

  1. 理解贪心算法的原理及一般应用。

  2. 思考贪心算法和动态规划法的区别。

  3. 编程实现典型的贪心算法,并对算法进行验证分析。

二. 实验内容

1.分别用动态规划、贪心法实现0-1背包问题,并对算法结果、效率进行比较分析。

实例:设n=4,价值向量V={12,11,9,8},重量向量为W={8,6,4,3},背包承重量为B=13。

2.编程实现活动安排问题。(教材89页表4.1)

1763556071475.png

1763556084633.png

1763556095578.png

3.编程实现教材111页4.3。

1763556106053.png

三. 实验结果

(1)0-1背包问题[动态规划]

input: n=4, V={12,11,9,8}, W={8,6,4,3}, B=13。

伪代码表述

输入:物品数 n,价值数组 v[1..n],重量数组 w[1..n],背包容量 B
输出:最大价值及其对应物品集合

初始化二维数组 dp[0..n][0..B] 为 0

for i 从 1 到 n:
    for j 从 1 到 B:
        if j < w[i]:
            dp[i][j] ← dp[i-1][j]
        else:
            dp[i][j] ← max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])

输出 dp[n][B]

j ← B
for i 从 n 递减到 1:
    if dp[i][j] > dp[i-1][j]:
        输出物品 i 的价值与重量
        j ← j - w[i]

源代码

// 动态规划实现0-1背包问题

// n=4,价值向量V={12,11,9,8},重量向量为W={8,6,4,3},背包承重量为B=13。
#include<bits/stdc++.h>
#define il inline
using namespace std;

#define pb push_back
#define fastio \
  ios::sync_with_stdio(false); \
  cin.tie(0);

typedef long long ll;
typedef unsigned long long ull;

const ll N = 5e5+5, mod = 1e9+7, inf = 2e18;
const double eps = 1e-9;
const double PI = 3.1415926;

il void solve(){
    int n = 4;
    vector<int> v = {12, 11, 9, 8};
    vector<int> w = {8, 6, 4, 3};
    const int b = 13;
    vector<vector<int>> dp(n+1, vector<int>(b+1, 0));
    for (int i = 1; i <= n;++i)
    {
        for (int j = 1; j <= b;++j)
        {
            // 剩余重量比当前物品重量还小,只能不装入背包
            if(j < w[i-1]){
                dp[i][j] = dp[i - 1][j];
            }else{
                // 装入背包或不装入背包
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]]+v[i-1]);
            }
        }
    }
    cout << dp[n][b] << '\n';
    int j = b;
    for (int i = n; i > 0;--i)
    {
        if (dp[i][j] > dp[i-1][j])
        {
            cout << "选择物品:" << i << " 价值:" << v[i-1] << " 重量:" << w[i-1] << '\n';
            j -= w[i-1];
        }
    }
}

int main()
{
    fastio
    
    int t = 1;
    // cin >> t;
    while(t--)
    {
        solve();
    }
    
    return 0;
}

运行结果

1763556178756.png

(2)0-1背包问题[贪心法] (是否对所有实例都能得到最优解?)

不是最优的,常见反例:价值/重量比高但重量大,贪心会选它导致剩余容量浪费

伪代码表述

输入:物品数 n,价值数组 v[1..n],重量数组 w[1..n],背包容量 B
输出:按单位价值贪心选取的总价值和物品集合

构造列表 ratio_list:
    对每个物品 i:
        ratio ← v[i] / w[i]        // 单位价值
        将 (ratio, i) 插入 ratio_list

按 ratio 从大到小对 ratio_list 排序

ans ← 0
wsum ← B
for (ratio, i) ∈ ratio_list:
    if wsum ≥ w[i]:
        ans ← ans + v[i]
        wsum ← wsum - w[i]

输出 ans

wsum ← B
for (ratio, i) ∈ ratio_list:
    if wsum ≥ w[i]:
        输出 “选择物品 i,价值 v[i],重量 w[i]”
        wsum ← wsum - w[i]

源代码

// 贪心算法实现0-1背包问题

// n=4,价值向量V={12,11,9,8},重量向量为W={8,6,4,3},背包承重量为B=13。
#include<bits/stdc++.h>
#define il inline
using namespace std;

#define pb push_back
#define fastio \
  ios::sync_with_stdio(false); \
  cin.tie(0);

typedef long long ll;
typedef unsigned long long ull;

const ll N = 5e5+5, mod = 1e9+7, inf = 2e18;
const double eps = 1e-9;
const double PI = 3.1415926;

il void solve(){
    int n = 4;
    vector<int> v = {12, 11, 9, 8};
    vector<int> w = {8, 6, 4, 3};
    const int b = 13;

    map<double, int, greater<int>> mp; //降序
    for (int i = 0; i < n;++i)
        mp.insert({1.0 * v[i]/w[i], i});

    int ans = 0;
    int wsum = b;
    for (auto it = mp.begin(); it != mp.end();++it)
    {
        if (wsum >= w[it->second])
        {
            ans += v[it->second];
            wsum -= w[it->second];
        }
    }
    cout << ans << '\n';

    wsum = b;
    for (auto it = mp.begin(); it != mp.end();++it)
    {
        if (wsum >= w[it->second])
        {
            cout << "选择物品:" << it->second + 1 << " 价值:" << v[it->second] << " 重量:" << w[it->second] << '\n';
            wsum -= w[it->second];
        }
    }
}

int main()
{
    fastio
    
    int t = 1;
    // cin >> t;
    while(t--)
    {
        solve();
    }
    
    return 0;
}

运行结果

1763556206295.png

活动安排问题

源代码

// 贪心算法实现活动安排问题

#include<bits/stdc++.h>
#define il inline
using namespace std;

#define pb push_back
#define fastio \
  ios::sync_with_stdio(false); \
  cin.tie(0);

typedef long long ll;
typedef unsigned long long ull;

const ll N = 5e5+5, mod = 1e9+7, inf = 2e18;
const double eps = 1e-9;
const double PI = 3.1415926;

typedef struct{
    int start;
    int finish;
}Activity;

vector<Activity> activities = {
    {0, 0}, // 占位不起作用
    {1, 4},
    {3, 5},
    {2, 6},
    {5, 7},
    {4, 9},
    {5, 9},
    {6, 10},
    {8, 11},
    {8, 12},
    {2, 13},
};

il void solve(){
    vector<int> ans;
    ans.pb(1);
    int j = 1;
    for (int i = 2; i < activities.size();++i)
    {
        if(activities[i].start >= activities[j].finish)
        {
            ans.pb(i);
            j = i;
        }
    }
    cout << "选择的活动: ";
    for (int i = 0; i < ans.size();++i)
    {
        cout << ans[i] << " ";
    }
    cout << '\n';
}

int main()
{
    fastio
    
    int t = 1;
    // cin >> t;
    while(t--)
    {
        solve();
    }
    
    return 0;
}

运行结果

1763556246166.png

  1. 找基站位置,并且使得基站总数达到最少。

伪代码表述

i ← 1, ans ← []

while i ≤ n:

    start ← d[i]

    station ← start + 4

    把 station 加入 ans

    while i ≤ n 且 d[i] ≤ station + 4:

        i ← i + 1

源代码

// 找基站位置,并且使得基站总数达到最少。

#include<bits/stdc++.h>
#define il inline
using namespace std;

#define pb push_back
#define fastio \
  ios::sync_with_stdio(false); \
  cin.tie(0);

typedef long long ll;
typedef unsigned long long ull;

const ll N = 5e5+5, mod = 1e9+7, inf = 2e18;
const double eps = 1e-9;
const double PI = 3.1415926;

vector<int> distance_a = {4, 5, 8, 12, 14, 15, 16, 18, 20, 22,30};

il void solve(){
    int i = 1;
    vector<int> ans;
    int n = distance_a.size() - 1;
    while(i <= n)
    {
        int start = distance_a[i];
        int station = start + 4;
        ans.pb(station);
        while (i <= n && distance_a[i] <= station + 4)
            ++i;
    }
    // 输出选择的基站的位置
    cout << "基站位置: ";
    for (int i = 0; i < ans.size();++i)
    {
        cout << ans[i] << " ";
    }
    cout << '\n';
}

int main()
{
    fastio
    
    int t = 1;
    // cin >> t;
    while(t--)
    {
        solve();
    }
    
    return 0;
}

运行结果

vector<int> distance_a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10};

1763556285034.png

vector<int> distance_a = {4, 5, 8, 12, 14, 15, 16, 18, 20,22,30};

1763556292870.png