动态规划()

本文详细介绍了动态规划算法的基本原理,包括如何通过阶段划分、确定状态和状态变量、写出状态转移方程以及找到边界条件。以过河卒、疯狂的采药和数字三角形问题为例,展示了动态规划在解决最优化问题中的应用和具体实现方法。
摘要由CSDN通过智能技术生成

动态规划:

所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。如图所示。动态规划的设计都有着一定的模式,一般要经历以下几个步骤。

    (1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。

    (2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。

    (3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。

    (4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

    一般,只要解决问题的阶段、状态和状态转移决策确定了,就可以写出状态转移方程(包括边界条件)。

实际应用中可以按以下几个简化的步骤进行设计:

    (1)分析最优解的性质,并刻画其结构特征。

    (2)递归的定义最优解。

    (3)以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值

    (4)根据计算最优值时得到的信息,构造问题的最优解

题目链接:过河卒

题解:dp问题 ,找出转移方程,注意些细节

AC代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip> 
#include <algorithm>
#include <cstdio>
#include <stack>
#include <queue>

using namespace std;

using ll = long long;
using ull = unsigned long long;
#define up(i, h, n) for (int  i = h; i <= n; i++) 
#define down(i, h, n) for(int  i = h; i >= n; i--)
#define wh(x) while(x--)
#define node struct node
#define it ::iterator
#define Ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
constexpr int MaxN = 500005;
constexpr int MaxM = 100005;
constexpr int mod = 1e9 + 7;
constexpr int inf = 0x7fffffff;

const int next1[8][2] = { {2, 1},  {1, 2}, {-2, -1}, {-1, -2}, {2, -1}, {-1, 2}, {-2, 1}, {1, -2} };
int x, y, m, n;
long long f[30][30];
bool book[30][30];
int main() {
	Ios;
	cin >> x >> y >> m >> n;
	x += 2; y += 2; m += 2; n += 2; // 防止越界初始化加2
	f[2][1] = 1; //初始化
	book[m][n]=true; // 标记马的位置
	up(i, 0, 7) {
		book[m + next1[i][0]][n + next1[i][1]] = true; // 标记马可以到的位置
	}
	up(i, 2, x) {
		up(j, 2, y) {
			if (book[i][j]==true)continue; 
			f[i][j] = f[i - 1][j] + f[i][j - 1]; //状态转移方程,是格子上方和格子左方
		}
	}
	cout << f[x][y];
	return 0;
}

题目链接:疯狂的采药

题解:完全背包问题,主要还是转移方程

AC代码:

#include<iostream>
#include<algorithm> 
#include<math.h>
#include<string.h>

using namespace std;

using ll=long long;
#define fo(h,n) for(int i=h;i<=n;i++)
#define whi(x) while(x--)
const int  N=10005,M=10000005;

ll dp[M],w[N],v[N];
int main()
{
	int t,m;
	cin>>t>>m;
	fo(1,m) cin>>w[i]>>v[i];
	fo(1,m){
		for(int j=w[i];j<=t;j++)
		   dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	}
	cout<<dp[t];
	return 0;
}

题目链接:数字三角形

题解:这个题的话我是从下往上递推,觉得从上往下难些

AC代码:

#include<iostream>
#include<algorithm> 
#include<math.h>
#include<string.h>
using namespace std;
using ll=long long;
#define fo(h,n) for(int i=h;i<=n;i++)
#define whi(x) while(x--)
const int  N=1005;
ll a[N][N];
int main()
{
	int n;
	cin>>n;
	fo(0,n-1){
		for(int j=0;j<=i;j++)
		   cin>>a[i][j];
	}
	for(int i=n-2;i>=0;i--){
		for(int j=0;j<=i;j++)
		a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
	}
	cout<<a[0][0];
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值