【C语言】动态规划法的设计与实现

122 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

【C语言】动态规划法的设计与实现

一、目的

掌握动态规划法的设计思想、具体实现和时间复杂度分析。

二、实验内容

先用伪代码或流程图描述利用动态规划解决的算法解决方案,再用程序实现,计算时间复杂度,记录最终测试数据和测试结果。
2.1实验内容:
2.1.1 斐波那契数列第n项的值。(自顶向下备忘 , 自底向上推导)
2.1.2 找零钱问题
2.1.3 多源点最短路径问题。
2.1.4爬台阶问题(设每次只能走一级或者两级台阶,请问走到第n级台阶一共有多少总走法)

三、设计和编码

3.1算法设计
3.1.1找零钱问题(P125,第8题)
输入:需要找的零钱
输出:零钱
1.定义ins=0,零钱种类change[]={100,50,20,10,5,2,1}
2.while(n > 0)
3.ans = n/change[i]
4.if(ans!=0)
5.sum_ans = sum_ans + ans
6.n = n - ans * change[i]

3.1.2多源点最短路径问题。
输入:点与边的关系
输出:最短路径
1.For k:=1 to n
2.For i:=1 to n
3.For j:=1 to n
3.1 If D[i,j]>D[i,k]+D[k,j] Then
3.1.1 D[i,j]:=D[i,k]+D[k,j];
3.1.3爬台阶问题(设每次只能走一级或者两级台阶,请问走到第n级台阶一共有多少总走法)
输入:要爬/跳的台阶数
输出:爬/跳法
1.若n==3,返回n,否则返回 Frog_jump(n - 2) + Frog_jump(n - 1);
2.输出ret;
3.2程序代码
3.2.1.斐波那契数列第n项的值。(自顶向下备忘 , 自底向上推导)
3.2.1.1自顶向下

#include<iostream>  
#include<cstdio>
using namespace std;
int F[1000]={0};
int f(int x){
    if(x==0){F[0]=1;return F[0];}
    if(x==1){F[1]=1;return F[1];}
    if(F[x])return F[x];//避免重复计算,有值立即返回
    else{
        F[x]=f(x-1)+f(x-2);
        return F[x];
    }
} 
int main(){
    int n;
    scanf("%d",&n);
    f(n);
    printf("F(%d)=%d\n",n,F[n]);
}

3.2.1.2自底向上

#include<iostream>
#include<cstdio>
using namespace std;
int F[1000000];
int main(){
    int n;
    scanf("%d",&n);
    F[0]=1;F[1]=1;
    for(int i=2;i<=n;i++){
        F[i]=F[i-1]+F[i-2];
    }
    printf("F(%d)=%d\n",n,F[n]);
}

3.2.2.找零钱问题

#include <stdio.h> 

int Coin(double m)
{
	printf("=====找零钱的方案为=====\n");
	int ans = 0; 
	int n;
	n = (int)(m*100);
	int change[]={100,50,20,10,5,2,1};
	int i = 0;
	int sum_ans = 0; 
	while(n > 0)
	{
		ans = n / change[i];
		if(ans != 0)
	{
	sum_ans = sum_ans + ans; 
	printf("需要找面额为%.2lf元的硬币个数为%d\n",1.0 * change[i] / 100, ans);	
	}
	n = n - ans * change[i];
	i++;
	}
	printf("需要找零的硬币总数为%d\n", sum_ans); 
	}

int main()
{
	double n; 	printf("请输入需要找给顾客的钱(单位:元、精确度为0.01):\n"); 
	scanf("%lf",&n);
	if((int)n*100 == 0)
	{
		printf("不需要找零钱\n"); 
	}
	else
	{
		Coin(n); 	
	}
	return 0; 
}

3.2.3.多源点最短路径问题

#include <iostream>
#include <cstring>
#include <string>

using namespace std;

long long dist[102][102]; //表示最大节点数是101个

long long minNum(long long a, long long b){
    if(a == -1) return b;
    return a < b ? a : b;
}

void floyd(long long dist[][102], int N){
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){
            for(int k = 1; k <= N; k++){
                if(dist[j][i] == -1 || dist[i][k] == -1){
                    continue;//如果没路径别走
                }
                dist[j][k] = minNum(dist[j][k], dist[j][i]+dist[i][k]);
            }
        }
    }
}

int main(){
    int N,M;

    while(cin>>N>>M){
        for(int i = 0; i <= N; i++){
            for(int j = 0; j <= N; j++){
                dist[i][j] = -1; //初始化为-1 表示无穷远
                if(i == j){
                    dist[i][j] = 0;
                }
            }
        }
        int x, y, d;
        for(int i = 0; i < M; i++){
            cin>>x>>y>>d;
            dist[x][y] = minNum(dist[x][y], d);
            dist[y][x] = dist[x][y];//无向图,如果是有向图去掉这个路径
        }
        floyd(dist, N);
        for(int i = 1; i <= N; i++){ //输出整个矩阵
            for(int j = 1; j<= N; j++){
                cout<<dist[i][j]<<" ";
            }
            cout<<endl;
        }
    }

    return 0;
}

3.2.4.爬台阶问题(设每次只能走一级或者两级台阶,请问走到第n级台阶一共有多少总走法)

#include <stdio.h>
#include <stdlib.h>
int Frog_jump(int n)
{
if (n < 3)
return n;
else
return Frog_jump(n - 2) + Frog_jump(n - 1);
}
int main()
{
int n = 0;
int ret = 0;
printf("请输入青蛙要跳的台阶数:");
scanf("%d", &n);
ret = Frog_jump(n);
printf("有%d种跳法\n", ret);
system("pause");
return 0;
}

四、运行结果及分析

4.1运行结果
4.1.1斐波那契数列第n项的值。(自顶向下备忘 , 自底向上推导)

image.png

时间复杂度:O(n)

4.1.2找零钱问题(P125,第8题)

image.png

时间复杂度:O(n)

4.1.3多源点最短路径问题

image.png

时间复杂度:O(n^2)

4.1.4爬台阶问题(设每次只能走一级或者两级台阶,请问走到第n级台阶一共有多少总走法)

image.png

时间复杂度:O(n)

4.2分析
用动态规划法进行程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。

五、实验小结

动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。因此在学习该方法时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。
我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法我们分析并解决了所有必做任务,并且对选做任务中的多个算法进行了简易的分析,并且计算出各个任务的时间复杂度。