动态规划入门part2

例2 :

在这样一个arr数组中

1234567

找出互不相临的n个数,使这些数的和最大。


依旧是一个求最优解的动态规划问题,求解的关键是找出每一个状态选和不选的指标函数。

选:

OPT(i) = OPT(i-2) + arr[i];

不选:

OPT(i) = OPT(i-1);

递归出口:

OPT(1) = arr[1];
OPT(2) = max(arr[1],arr[2]);

这时已经可以写出递归求解方法:

#include <iostream>
#include <algorithm>
using namespace std;

int arr[10] = {0,1,2,4,1,7,8,3};

int rec_opt(int n) //rec_opt即上文中OPT,rec代表递归recursion
{
    if(n == 1)
        return 1;
    else if(n == 2)
        return max(arr[1],arr[2]);
    int x1,x2;//x1是选的状态,x2是不选的状态
    x1 =rec_opt(n-2)+arr[n];
    x2 =rec_opt(n-1);
    return max(x1,x2);
}

int main()
{
    cout << rec_opt(7) <<endl;
    return 0;
}

画出树形图:
树形图
如OPT(3)和OPT(4),递归求解过程存在重叠子结构。

在动态规划算法中使用opt数组记录每一个状态

#include <iostream>
#include <algorithm>
using namespace std;

int arr[10] = {0,1,2,4,1,7,8,3};
int opt[10];
int dp_opt(int n)//rec代表是递归recursion
{
    opt[1] = arr[1];
    opt[2] = max(arr[1],arr[2]);
    for(int i=3;i<=n;i++)
    {
        int x1,x2;//x1是选的状态,x2是不选的状态
        x1 =dp_opt(i-2)+arr[i];
        x2 =dp_opt(i-1);
        opt[i] = max(x1,x2);
    }
    return opt[n];
}

int main()
{
    cout << dp_opt(7) <<endl;
    return 0;
}
例题3 :

在这样一个arr数组中

33441252

输入一个整数s,如果存在数组中的n数之和等于s则输出true,否则输出false。

本题依旧是求最优解的问题,求解的关键是找出每一个状态选和不选的指标函数。
定义subset(i,s)函数 ,第一个参数表示数组中当前位置i之前的所有数可选,s表示还需要的和 (subset是子集的意思)。

当s输入为9时
如果选arr[5] (arr[5] = 2)

subset(arr[5],9) = arr[5]+subset(arr[4],7);

如果不选arr[5]

subset(arr[5],9) = subset(arr[4],9));

递归出口:
1.s已经等于0时

if(s == 0)
	return true;

2.当i = 0,s不等于0时

if(i == 0 && arr[i] == s)
	return true;
else
	return false;

3.当arr[i]>s时,不考虑选的情况

if(arr[i]>s)
	return(subset(arr[i-1],s));

递归算法:

#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,3,34,4,12,5,2};

bool rec_opt(int n,int s)
{
    if (s == 0)
        return true;
    else if(n == 1 && s!= arr[1])
        return false;
    else if(n == 1 && s == arr[1])
        return true;
    else if(arr[n] > s)
        return rec_opt(n-1, s);
    else
    {
        bool x1,x2;
        x1 = rec_opt(n-1,s-arr[n]);
        x2 = rec_opt(n-1, s);
        return (x1 || x2);
    }
}

int main()
{
    int s;
    cin >> s;
    if(rec_opt(6, s))
        cout << "true" << endl;
    else
        cout << "false" << endl;
    return 0;
}

动态规划:
dp

#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,3,34,4,12,5,2};
bool opt[10][101];

bool dp_opt(int n,int s)
{
    bool x1,x2;
    for(int i=0;i<=6;i++)
        opt[i][0] = true;
    for(int i=0;i<=101;i++)
        opt[1][i] = false;
    opt[1][4] = true;
    
    for(int i=1;i<=6;i++)
        for(int j = 0;j <= s;j++)
            if(arr[i] > j)
                opt[i][j] = opt [i-1][j];
            else
            {
                x1= opt[i-1][j-arr[i]];
                x2 = opt[i-1][j];
                opt[i][j] = (x1 || x2);
            }
    return opt[6][s];
}

int main()
{
    int s;
    cin >> s;
    if(dp_opt(6, s))
        cout << "true" << endl;
    else
        cout << "false" << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值