C++动态规划算法学习&练习

写在前面

前面的内容一直到Jump Game是看了b站的九章算法动态规划班免费的课的过程中的记录~ 这里是链接~老师说得很好,但是这个课好贵啊TATlink
后面是九章算法老师布置的作业和算法设计与分析老师布置的作业 ~
刚刚看到一个python课程收藏在这里哈哈哈哈link
之前看的OpenCV+Python的课也放一下~link
OpenCV:link
再存一下Java微信实现支付的demo(反正也没人看,我自己好找)link

动态规划题目特点

1.计数
-有多少种方式走到右下角
-有多少种方法选出k个数使得和是Sum

2.求最大最小值
-从左上角走到右下角路径的最大数字和
-最长上升子序列长度

3.求存在性
-取石子游戏,先手是否必胜
-能不能选出k个数使得和是Sum

动态规划步骤

例题:2,5,7三种硬币,取最小的硬币付清27元的商品。
动态规划组成部分:
1.确定状态
-最后一步(最优策略中使用的最后一枚硬币 a k a_{k} ak
-化成子问题(最少的硬币拼出更小的面值27- a k a_{k} ak
2.转移方程
-f[X]=min{f[X-2]+1,f[X-5]+1,f[X-7]+1}
3.初始条件和边界情况
-初始条件是用转移方程算不出的存在情况,需要手动设置
-边界情况是为了确保不越界
-f[0]=0,如果不能拼出Y,f[Y]=正无穷
4.计算顺序
-f[0],f[1],[2],…
-需要用的肯定是以及算好的
消除冗余,加速计算~

做题

Coin Change–最大最小值

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

Note:
You may assume that you have an infinite number of each kind of coin.

#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
                //{2,5,7} //27
int coinchange(vector<int> a,int M)
{
    int f[M+1];
    int n=a.size();//the number of kinds of coins
    //initialization
    f[0]=0;
    for(int i=1;i<=M;++i){
        f[i]=INT_MAX;
        //f[i]=min{f[i-a[0]]+1,...,f[i-a[n-1]]+1}
        for(int j=0;j<n;++j){
            if(i>=a[j] && f[i-a[j]]!=INT_MAX){
                f[i]=min(f[i],f[i-a[j]]+1);
            }
        }
    }
    if(f[M]==INT_MAX){
        f[M]=-1;
    }
    return f[M];
}

int main()
{
    vector<int> arr;
    int temp,total;
    while(cin >> temp && getchar()!='\n'){
        arr.push_back(temp); //填充数据
    }
    arr.push_back(temp);
    //因为上面getchar()!='\n'使最后的temp没有保存到arr
    cin>>total;
    cout<<coinchange(arr,total);
}

第一次用vector,太香了我哭!

Unique Paths–计数问题

题意:m行n列网格,一个机器人从左上角(0,0)出发,每一步可以向下或者向右走一步,一共有多少种不同的走法走到右下角。

分析:最后一步,不论何种方式走到右下角(m-1,n-1),前一步一定是(m-2,n-1)或者(m-1,n-2)。
加法原则:无重复无遗漏
此时通过(m-2,n-1)走到(m-1,n-1)的方式加上通过(m-1,n-2)走到(m-1,n-1)的方式就是所求,子问题为(m-1,n-2)和(m-2,n-1)
以上是第一步确定状态。设f[i][j]为机器人有多少种方式从左上角走到(i,j)。
状态转移方程为:f[i][j]=f[i-1][j]+f[i][j-1]
下面考虑初始条件和边界情况:
初始条件:f[0][0]=1,机器人只有一种方式到左上角
边界情况:i=0 or j=0,则前进一步只有一个方向可以过来,f[i][j]=1
最后我们看一下计算顺序
f[0][0]=1,然后依次算每一行~~就正常的遍历数组就好了,答案是f[m-1][n-1]
时间复杂度:每一步都算了,O(mn),空间复杂度:开了一个f[m][n]数组,记录每一步状态~所以也是O(mn)

#include <iostream>
#include <stdio.h>
using namespace std;

int uniquepaths(int m,int n){
    int f[m][n];
    int i,j;
    for(i=0;i<m;++i){
        for(j=0;j<n;++j){
            if(i==0 || j==0){
                f[i][j]=1;
            }
            else{
                f[i][j]=f[i-1][j]+f[i][j-1];
            }
        }
    }
    return f[m-1][n-1];
}

int main(){
    int m,n;
    cin>>n>>m;
    cout<<uniquepaths(m,n);
}

Jump Game–求存在性

题意:有n块石头分别在x轴的0,1,…,n-1位置,有一只青蛙在石头0处,想要跳到石头n-1处,如果青蛙在第i块石头上,它最多可以向右跳距离 a i a_i ai,问青蛙能否跳到石头n-1。
examples:
input:a=[2,3,1,1,4]
output:True
input:a=[3,2,1,0,4]
output:False

分析:
1.首先确定状态:如果存在,那么最后一步是跳到了n-1上,那么之前一个石头为i,i到n-1的距离小于 a i a_i ai即可。即n-1-i<=a[i],若将能否跳到n-1设为f[n-1],那么子问题为f[i]。
2.转移方程:f[j]= O R 0 < = i < j OR_{0<=i<j} OR0<=i<j(f[i] AND i+a[i]>=j),这里OR的意思是只要存在一个i满足条件即可。
3.初始条件和边界情况:初始条件:f[0]=True,没有边界情况,应该枚举的i都不会越界。
4.计算顺序:从左到右,从小到大算,因为算后面的话, 前面必须算出来,时间复杂度为O( N 2 N^2 N2),空间复杂度为O(N)。

#include <iostream>
#include <vector>
#include <stdlib.h>
using namespace std;

bool canJump(vector<int> a) {
	int n = a.size();
	int f[100];
	f[1] = true;
	for (int j = 2; j <= n; j++){
		f[j] = false;
		//previous stone i
		//last jump is from i to j
		for (int i = 1; i < j; i++) {
			if (f[i] && i + a[i] >= j) {
				f[j]=true;
				break;
			}
		}
	}
	return f[n];
}

int main() {
	vector<int> a;
	int temp;
	while (scanf("%d", &temp) && getchar() != '\n') {
		a.push_back(temp);
	}
	a.push_back(temp);
	cout << canJump(a);
}

Homework:Maximum Product Subarray

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.
翻译:给定一个整数数组nums,在其中找到连续的子数组(至少包含一个数字)具有最大的乘积。
Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.
Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
分析:首先确定状态,给定数组f[i]记录从左向右找到的包含a[i]的数组的最大乘积,最后一步为f[n],最后求max(f[])即可。接下来看状态转移方程,f[i]=max{f[i-1]*a[i],a[i]},接下来考虑边界情况和初始情况,初始f[0]=a[0],不会越界。计算顺序是按照f[0],f[1],…,f[n-1]来计算的,时间复杂度为O(n),空间复杂度为O(n)。

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

int Max_Pro_Sub(vector<int> a) {
	int n = a.size();
	int f[100];
	f[0] = a[0];
	int maxn = f[0];
	for (int i = 1; i < n; i++) {
		f[i] = max(f[i - 1] * a[i], a[i]);
		maxn = max(maxn, f[i]);
	}
	return maxn;
}

int main(){
	vector<int> a;
	int temp;
	while (scanf("%d", &temp) && getchar() != '\n') {
		a.push_back(temp);
	}
	a.push_back(temp);
	cout << Max_Pro_Sub(a);
}

明天要上贪心法了,所以今晚打算把贪心法篇也写一点^ ^

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值