算法设计与分析实验报告-动态规划算法

 校课程的简单实验报告。

算法设计与分析实验报告-递归与分治策略

算法设计与分析实验报告-动态规划算法

算法设计与分析实验报告-贪心算法 

        dijkstra迪杰斯特拉算法(邻接表法)

算法设计与分析实验报告-回溯法

算法设计与分析实验报告-分支限界法 

算法设计与分析实验报告-分治法相关练题

北京大学出版社-算法设计与分析


目录

一、实验目的

二、实验内容

三、实验环境

四、实验步骤及说明

五、实验小结及思考


一、实验目的

    1.理解动态规划算法的概念;

    2.掌握动态规划算法的基本要素;

    3.掌握设计动态规划算法的步骤和策略。

二、实验内容

使用动态规划法求解以下问题,要求给出程序代码,并编译运行程序:

1. 币值问题。

给定不同面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回-1。

示例1如下。

输入:coins=[1,2,5],amount=11

输出:3

解释:11=5+5+1

示例2如下。

输入:coins=[2], amount= 3

输出:-1

说明:你可以认为每种硬币的数量是无限的。

实质上该题是LeetCode322.零钱兑换

        给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

        计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

        你可以认为每种硬币的数量是无限的。

2.航线问题。

美丽的莱茵河河畔,每边都有N个城市,并且每个城市都有唯一的对应友好城市。因为莱茵河上经常大雾,所以要制定航线,每个航线不可以交叉。现在要求出最大的航线数目。

输入:有若干组测试数据,每组测试数据第一行输入n,接着n行输入a、b表示a城市与b城市通航。(1≤n≤1000)。

输出:最大的航线数。

示例如下。

输入:

4

1 2

2 4

3 1

4 3

8

1 3

4 4

3 5

8 6

6 8

7 7

5 2

2 1

输出:

2

3

实质上是LeetCode300.

        给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

        子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

3.数组均衡划分问题。

给定一组整数,任务是将其分为两组Subset1和Subset2,使得它们的和之间的绝对差最小。

如果有一个集合S有n个元素,那么如果假设Subset1有m个元素,那么Subset2必须有n-m个元素,abs(sum(Subset1)-sum(Subset2)) 的值应该是最小的。

示例如下。

输入:arr[]= {1,6,11,5}

输出:1

解释:s1={1,5,6},sum=12,s2={11},sum=11

三、实验环境

1. 使用的操作系统及版本:

Windows 10

2. 使用的编译系统及版本:

Clion 2022.2.3

四、实验步骤及说明

1、币值问题

代码如下:

//
// Created by GiperHsiue on 2022/11/2.
//
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
// 币值问题
//O(S*n) O(S)
//F(i) = min{F(i - Ci)} + 1
int coinsAmt(vector<int> coins, vector<int>& trace, int amount){
    vector<int> F (amount + 1, amount + 1);
    F[0] = 0;
    int count = coins.size();
    for(int i = 1; i <= amount; i ++){
        for(int j = 0; j < count; j ++){
            if(i - coins[j] < 0) continue;
            else{
                F[i] = min(F[i - coins[j]] + 1, F[i]);
                if(F[i] == F[i - coins[j]] + 1) trace[i] = coins[j];
            }
        }
    }

    return  F[amount] == amount + 1 ? -1 : F[amount];
}
// 方案路径
void findPath(vector<int> trace, int amount){
    if(!amount) return;
    findPath(trace, amount -trace[amount]);
    if(amount -trace[amount] == 0) cout << trace[amount];
    else cout << " + " << trace[amount];
}

int main(){
    cout << "输入币值种类个数:";
    int n;
    cin >> n;
    vector<int> coins(n);
    vector<int> trace(100, 0);
    for(int i = 0; i < n; i ++) cin >> coins[i];
    cout << "输入总金额:";
    int amount;
    cin >> amount;
    int res = coinsAmt(coins, trace, amount);
    cout << "最小硬币数量:" << res << endl;
    if(res != -1) {
        cout << amount << " = ";
        findPath(trace, amount);
    }
    return 0;
}

运行如下:

2.航线问题

代码如下:

//
// Created by Giperx on 2022/11/3.
//
// 航线问题
// 按a城市编号大小sort后,求最长上升子序列
// F[i] = max{F[i - 1] + 1, F[i]} A[i - 1] < A[i]
#include <iostream>
#include <vector>
using namespace std;
int lines(vector<int>& a){
    int n = a.size();
    int res = -1;
    vector<int> F(n, 1);
    for(int i = 0; i < n; i ++) {
        for (int j = 0; j < i; j++) {
            if (a[j] < a[i]) {
                F[i] = max(F[i], F[j] + 1);
            }
        }
        res = max(res, F[i]);
    }

    return res;
}
int main(){
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        vector<int> a(n, 0);
        for(int i = 0; i < n; i ++){
            int tmp1, tmp2;
            cin >> tmp1 >> tmp2;
            a[tmp1 - 1] = tmp2;
        }
        cout << lines(a);
    }
    return 0;
}

运行如下:

3.数组均衡划分问题

代码如下:

//
// Created by GiperHsiue on 2022/11/3.
//
// 数组均衡划分问题
// Subset1 尽量找到总和 接近 sums/2的子序列,本质01背包问题
// F[i][s] = max{F[i - 1][s], F[i - 1][s - arr[i]] + arr[i]}
// F[s] = max{F[s], F[s - arr[i]] + arr[i]}
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int absMin(vector<int> arr){
    int sums = 0;
    for(auto tmp:arr) sums += tmp;//总和sums
    int *F = new int[int(sums/2) + 1](); // 状态数组初始化


    for(int i = 0; i < arr.size(); i ++) {
        for (int j = sums / 2; j >= arr[i]; j--)
            F[j] = max(F[j], F[j - arr[i]] + arr[i]);
//        for(int j = 0; j <= sums/2; j ++) cout << F[j] << ' ';
//        cout << endl;
    }
    return F[int(sums/2)];
}
int main(){
    int n, sums = 0;
    cin >> n;
    vector<int> arr(n, 0);
    for(auto &tmp:arr) cin >> tmp, sums += tmp;
    int res = absMin(arr);
    cout << sums - 2 * res;
    return 0;
}

运行如下:


五、实验小结及思考

通过本次实验,我对于动态规划算法的概念加深理解,进一步掌握动态规划算法的基本要素,也进一步掌握设计动态规划算法的步骤和策略。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值