动态规划方法之一:制表
为什么要用动态规划:
动态编程是一种算法范例,通过将其分解为子问题来解决给定的复杂问题,并存储子问题的结果,以避免再次计算相同的结果。 以下是一个问题的两个主要属性,表明给定的问题可以使用动态编程来解决。
1。重叠子问题
2. 最优子结构
a)记忆(自上而下)
b)制表(从上到下)
下面我们就从最简单的斐波那契 的动态规划开始!由于本身比较简单所以我就简单说说,主要讨论后面两个例子!
#include<stdio.h>
#define NIL -1
#define MAX 100
intlookup[MAX];//这里是一个备忘录
/* Function to initialize NIL values in lookup table */
void_initialize()
{
inti;
for(i = 0; i < MAX; i++)
lookup[i] = NIL;
}
/* function for nth Fibonacci number */
intfib(intn)
{
if(lookup[n] == NIL)
{
if(n <= 1)
lookup[n] = n;
else
lookup[n] = fib(n-1) + fib(n-2);
}
returnlookup[n];
}
intmain ()
{
intn = 40;
_initialize();
printf("Fibonacci number is %d ", fib(n));
return0;
}
#include<stdio.h>
intfib(intn)
{
intf[n+1];
inti;
f[0] = 0; f[1] = 1;
for(i = 2; i <= n; i++)
f[i] = f[i-1] + f[i-2];
returnf[n];
}
intmain ()
{
intn = 9;
printf("Fibonacci number is %d ", fib(n));
return0;
}
好了,这只是引子帮助大家理解的,我也不多说了, 下面我们来看最长增长序列的问题
让我们讨论最长增长子序列(LIS)问题作为可以使用动态编程解决的示例问题。
最长增长子序列(LIS)问题是找到给定序列的最长子序列的长度,使得子序列的所有元素按增加的顺序排序。
例如,{10,22,9,33,21,50,31,60,80}的LIS长度为6,LIS为{10,22,33,50,60,80}}。
首先我们看到题目,先判断能不能用动态规划的方法。我来说一下我思考的过程:
1.我需要用arr[i]来存储数据,用i对数组的数据进行遍历
2.我需要另一个变量j来遍历i前面的数字,如果arr[j] < arr[i],所以立马你就知道你现在需要一个数组来从最初的i存储LIS
了
3.我需要一个表,我需要一个数组lis[]来作为表格记录每次到达之前最长增长序列i的长度,后面出现重叠子问题直接调用;
|
#include<stdio.h> |
题目描述:
给定一个非负整数数组,假定你的初始位置为数组第一个下标。数组中的每个元素代表你在那个位置能够跳跃的最大长度。你的目标是到达最后一个下标,并且使用最少的跳跃次数。
例如:
A = [2,3,1,1,4], 到达最后一个下标的最少跳跃次数为2.(先跳跃1步,从下标0到1,然后跳跃3步,到达最后一个下标。一共两次)
格式:
第一行输入一个正整数n,接下来的一行,输入数组A[n]。
最后输出最少的跳跃次数。
样例:
输入
5
3 1 1 1 1
输出
2
题目描述:
给定一个非负整数数组,假定你的初始位置为数组第一个下标。数组中的每个元素代表你在那个位置能够跳跃的最大长度。你的目标是到达最后一个下标,并且使用最少的跳跃次数。
例如:
A = [2,3,1,1,4], 到达最后一个下标的最少跳跃次数为2.(先跳跃1步,从下标0到1,然后跳跃3步,到达最后一个下标。一共两次)
格式:
第一行输入一个正整数n,接下来的一行,输入数组A[n]。
最后输出最少的跳跃次数。
样例:
输入
5
3 1 1 1 1
输出
2
1.在下面二重循环时,j为什么要小于i?
2.我觉得这个问题没有最优啊,只有一种情况,这个题目有个跳跃游戏一,那个我做出来了而且稍微改一下也可以得到这道题的答案,
但是那道题我就按照自己的思路感觉很简单就出来了,对了我一会试一下在一的基础上能不能改成二动态规划。
3. if(dp[j] + 1 < dp[i])
dp[i] = dp[j] + 1;
// dp[i] = min(&dp[i], &dp[j]+1);
前两局为什么不能用第三句代替呢?
我会在下面代码的注释中解释:
#include<stdio.h>
#include<stdlib.h>
#define MAX 99999
int min(int *a, int *b);
int BestJump(int a[], int len, int *dp);
//动态规划 跳跃二
int main()
{
int n;
int *dp;//申请一个动态数组作为表
printf("请输入元素个数:\n");
scanf("%d", &n);
int a[n];
printf("请输入元素:\n");
for(int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
}
printf("跳跃了%d次!", BestJump(a,n,dp));
return 0;
}
int BestJump(int a[], int len, int *dp)
{
if(len <= 1)
{
return 0;
}
dp = (int *)malloc((len+1)*sizeof(int));
dp[0] = 0;//下面三行代码是表格的初始化
for(int i = 1; i < len; ++i)
{
dp[i] = MAX;
}
//从数组下标为一的元素开始遍历
for(int i = 1; i < len; ++i)
{
for(int j = 0; j < i; ++j)//这里之所以要小于i是因为我们每一次求得的dp[i]都是i之前需要跳跃的次数,当时我这里一直不明白,其实是因为我没有弄明白这个问题的算法
{
if(a[j] + j >= i)
{
if(dp[j] + 1 < dp[i])
dp[i] = dp[j] + 1;
// dp[i] = min(&dp[i], &dp[j]+1);
break;
}
}
}
return dp[len -1];
}
int min(int *a, int *b)
{
return ((*a)<(*b)?(*a):(*b));
}
至于为啥是最少即最优问题我想这里面可能有贪心的成分吧,就比如a[0] = 3,他可以跳跃到达a[3],a[2],a[1];#include<stdio.h>
#include<stdlib.h>
#define MAX 99999
int min(int *a, int *b);
int BestJump(int a[], int len, int *dp);
//动态规划 跳跃二
int main()
{
int n;
int *dp;
printf("请输入元素个数:\n");
scanf("%d", &n);
int a[n];
printf("请输入元素:\n");
for(int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
}
printf("跳跃了%d次!", BestJump(a,n,dp));
return 0;
}
int BestJump(int a[], int len, int *dp)
{
if(len <= 1)
{
return 0;
}
dp = (int *)malloc((len+1)*sizeof(int));
dp[0] = 0;
for(int i = 1; i < len; ++i)
{
dp[i] = MAX;
}
for(int i = 1; i < len; ++i)
{
for(int j = 0; j < i; ++j)
{
if(a[j] + j >= i)
{
if(dp[j] + 1 < dp[i])
dp[i] = dp[j] + 1;
// dp[i] = min(&dp[i], &dp[j]+1);
break;
}
}
}
return dp[len -1];
}
int min(int *a, int *b)
{
return ((*a)<(*b)?(*a):(*b));
}
#include<stdio.h>
#include<stdlib.h>
#define MAX 99999
int min(int *a, int *b);
int BestJump(int a[], int len, int *dp);
//动态规划 跳跃二
int main()
{
int n;
int *dp;
printf("请输入元素个数:\n");
scanf("%d", &n);
int a[n];
printf("请输入元素:\n");
for(int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
}
printf("跳跃了%d次!", BestJump(a,n,dp));
return 0;
}
int BestJump(int a[], int len, int *dp)
{
if(len <= 1)
{
return 0;
}
dp = (int *)malloc((len+1)*sizeof(int));
dp[0] = 0;
for(int i = 1; i < len; ++i)
{
dp[i] = MAX;
}
for(int i = 1; i < len; ++i)
{
for(int j = 0; j < i; ++j)
{
if(a[j] + j >= i)
{
if(dp[j] + 1 < dp[i])
dp[i] = dp[j] + 1;
// dp[i] = min(&dp[i], &dp[j]+1);
break;
}
}
}
return dp[len -1];
}
int min(int *a, int *b)
{
return ((*a)<(*b)?(*a):(*b));
}

3526

被折叠的 条评论
为什么被折叠?



