超详细!动态规划详解分析(典型例题分析和对比,附源码)

为啥要使用动态规划?什么时候使用动态规划?以下是我的一些理解和心得,如果你感兴趣,就接着往下看吧。
对您有帮助的话记得给我点个赞哟!在这里插入图片描述

动态规划的基本思想

动态规划(Dynamic Programming,DP)算法通常用于求解某种具有最优性质的问题。在这类问题中,可能会有许多可行解,每一个解都对应一个值,我们希望找到具有最优值的解
动态规划算法与分治法类似,其基本思想也是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中 得到原有问题的解。与分治法不同的是,动态规划经分解后得到的子问题往往 不是相互独立 的。

(分治算法也可以解决分解后得到的子问题不是相互独立的情况,只是要对公共子问题进行单独求解。这样会使分治法求解问题的复杂度大大提高。对此类问题如果感兴趣的话可以看我的另外一篇文章——分治法详细讲解。)

为什么要使用动态规划算法?

有些问题明明可以用递归实现,为什么还要用动态规划实现呢?下面我们看一个经典的例子:

例:斐波拉契数列

Fibonacci(斐波拉契数列)问题,它是一个简单而典型的分治问题,Fibonacci数列的递归方程表示为:
在这里插入图片描述

递归实现代码

#include<stdio.h>
int main(){
	int F(int n);
	printf("%d\n",F(5));
	return 0;
}
//Fibonacci数列的递归算法
int F(int n){
	if(n<=1){
		return 1;
	}
	else{
		return F(n-1)+F(n-2);
	}
}

该程序实现简单,但是效率非常低。因为在递归调用过程中,有些子问题被反复计算多次,例如 :

其中F(3)被计算了两次
F(4)=F(3)+F(2)
F(3)=F(2)+F(1);

那怎样解决这个问题呢?
如果用一个数组保存已解决的子问题的答案,而在需要的时候再从数组中查找出已求得子问题的答案,这样就可以避免大量的重复计算。这种就是动态规划算法:
动态规划算法代码:

#include<stdio.h>
int main(){
	int Fibonacci(int n);
	printf("%d\n",Fibonacci(5));
	return 0;
}
int Fibonacci(int n){
	//申请一个数组存放子问题的解 
	int f[n+1],i;
	f[0]=1;
	f[1]=1;
	for(i=2;i<=n;i++){
		f[i]=f[i-1]+f[i-2];
	}
	return f[n];
}

动态规划算法需要存储各子问题的解,所以它的空间复杂度要大于其他算法,这是一种空间换时间的策略。

怎样使用动态规划算法?

以下是动态规划的求解步骤:

1.分析最优子结构性质(递推关系)
2.递归定义最优值(动态规划核心)
3.自底向上的方式计算出最优值(动态规划的执行过程)
4.根据计算最优值时得到的信息,构造最优解

下面我们将通过一个例子来对比动态规划的应用和贪心算法和动态规划有什么不同。

例:数字三角形

如图所示,有一个群岛,共分为若干层,第1层有一个岛屿,第2层有2个岛屿,……,第n层有n个岛屿。每个岛上都有一块宝,其价值是一个正整数(图中圆圈中的整数)。寻宝者只允许从第一层的岛屿进人,从第n层的岛屿退出,不能后退,他能收集他所经过的所有岛屿上的宝贝。但是,从第i层的岛屿进入第i计1层的岛屿时,有且仅有有2条路径。你的任务是:对于给定的群岛和岛上宝贝的价值,计算一个寻宝者行走一趟所能收集宝贝的最大价值。
在这里插入图片描述

思路:
这个问题可以抽象为数字三角形问题,要求从顶部出发,在每一个节点可以选择向左走或者向右走,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
数据存储:
我们可以将数字三角形存储在一个二维数组里。

num01234
09
11215
21068
321895
419710416

贪心算法和动态规划的比较:
贪心算法是自顶向下求解,只能选择眼前对自己最有利的一步,其他的路径看不见。
动态规划是自底向上求解,逐层递推。

贪心算法实现:

我们使用贪心算法没法找到真正的最大和(最优解)。是用贪心算法所走的路径为:9+15+8+9+10=51。贪心算法是自顶向下解决问题的,它只能看到眼前的路,并选择对自己最有利的一步,而看不到其他的路径。
在这里插入图片描述
关键:

对于num[i][j],只需比较num[i+1][j]和num[i+1][j+1],哪个数字大选择哪条路.

源代码:

//贪心算法实现数字三角形 
#include<stdio.h>
int result=0;
int main(){
	void tanxin(int a[5][5],int h,int l);//传入数组进行贪心选择 h为行数,l为列数 
	int i,j;
	//数组填入采用初始化的形式(今天不是主角)
	int num[5][5]={0};//全部初始化为0
	num[0][0]=9;
	num[1][0]=12;num[1][1]=15;
	num[2][0]=10;num[2][1]=6;num[2][2]=8;
	num[3][0]=2;num[3][1]=18;num[3][2]=9;num[3][3]=5;
	num[4][0]=19;num[4][1]=7;num[4][2]=10;num[4][3]=4;num[4][4]=16;
	//初始化完毕
	//输出数组
	printf("输出初始化过后的数组\n");
	for(i=0;i<5;i++){
		for(j=0;j<5;j++){
			if(num[i][j]!=0)
			printf("%d  ",num[i][j]);
		}
		printf("\n");
	} 
	//贪心选择开始 
	tanxin(num,5,5);
	printf("贪心算法计算的数字和为:%d\n",result);
	return 0;	
}
void tanxin(int a[5][5],int h,int l){
	//拿到数组进行选择
	result=a[0][0];
	int i,j;
	for(i=1;i<h;i++) {
		j=i;		
		if(a[i][j+1]!=0){
			if(a[i+1][j]>=a[i+1][j+1]) result=result+a[i+1][j];
			else result=result+a[i+1][j+1];
		}
	}
	return result;
}
动态规划实现

我们自底向上,逐层递推,把较大的数字与上一层相加,把得到的数字存到解的数组中(避免重复计算),加到最后就是本题最优解。

例如:
在这里插入图片描述
在图中,19+2>7+2,所以把19与上一层相加

在这里插入图片描述
自底向上,逐层向上相加,并把计算的结果存储到结果数组中。
关键:

对于num[i][j],比较num[i-1][j],num[i-1][j-1]哪个大,num[i][j]与哪个相加
题中我从num[3][0]开始,与下面的num[4][0]与 num[4][1]比较,因为num[4][0]比较大,num[4][0]与num[3][0]相加

源代码:

//动态规划实现数字三角形
#include<stdio.h>
int result=0; 
int main(){
	//自底向上,眼着全局 
	int dongtaiguihua(int a[5][5],int h,int l);
	//数组填入采用初始化的形式(今天不是主角)
	int num[5][5]={0};//全部初始化为0
	num[0][0]=9;
	num[1][0]=12;num[1][1]=15;
	num[2][0]=10;num[2][1]=6;num[2][2]=8;
	num[3][0]=2;num[3][1]=18;num[3][2]=9;num[3][3]=5;
	num[4][0]=19;num[4][1]=7;num[4][2]=10;num[4][3]=4;num[4][4]=16;
	//初始化完毕 
	result=dongtaiguihua(num,5,5);
	printf("动态规划计算的数字和为:%d\n",result);
	return 0;
} 
int dongtaiguihua(int a[5][5],int h,int l){
	int i,j;
	for(i=h-2;i>=0;i--){
		for(j=0;j<=i;j++){
			if(a[i+1][j]>a[i+1][j+1]) a[i][j]+=a[i+1][j];
			else a[i][j]+=a[i+1][j+1];
		}
	}
	return a[0][0];
}

运行结果:
在这里插入图片描述


写到最后

感谢您看到这里,对您有帮助的话点个赞再走呀!ε = = (づ′▽`)づ 谢谢!!

SPSS是一种广泛应用于数据分析的统计软件,其中主成分分析(Principal Component Analysis,PCA)是一项常用的数据降维技术。本文将通过一个例题详细解释SPSS中主成分分析的过程。 假设我们有一份包含10个变量的数据集,每个变量代表某个商品的不同特征。我们希望通过主成分分析来减少这些特征的数量,从而更好地理解数据。 首先,我们需要打开SPSS软件并导入数据集。在“数据”菜单中选择“导入数据”选项,然后选择正确的数据文件。确认数据正确导入后,我们可以开始主成分分析。 在“分析”菜单中选择“数据降维”选项,然后选择“主成分”。在弹出的对话框中,选择要进行主成分分析的变量,并确定是否进行标准化。标准化可以将各个变量的值转换为标准分数,使得不同变量之间具有可比性。如果变量之间的度量单位不同,建议进行标准化操作。 接下来,我们需要确定保留多少个主成分。常用的方法是通过查看“累计方差贡献率”曲线来确定。该曲线显示每个主成分对总方差的贡献程度。一般情况下,我们会选择保留累计方差贡献率大于80%的主成分。 分析完成后,SPSS会生成一个主成分分析的结果表格。表格中包含了每个主成分的贡献率、特征值、因子载荷、因子得分等信息。贡献率表示该主成分解释了数据总方差的多少,特征值表示该主成分的重要程度,因子载荷表示变量与主成分之间的相关性,因子得分表示每个样本在每个主成分上的得分情况。 在分析结果中,我们可以根据因子载荷和因子得分来解释主成分的含义。较高的因子载荷表示变量与主成分之间的相关性较强,可以认为这些变量对于主成分的解释更为重要。而较高的因子得分表示样本在该主成分上的得分较高,说明该样本在该特征上具有较大的影响力。 综上所述,通过SPSS的主成分分析,我们可以减少变量的数量,提取出主要的特征,从而更好地理解和解释数据。这对于数据处理、模型建立和预测分析等领域都具有重要的应用价值。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nan_black

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值