算法设计与分析—动态规划例题

问题A:FIB数列(备忘录)

题目描述

求FIB数列第n项的值

输入

输入一个整数n,表示需要输出FIB数列第n项的值

输出

输出FIB数列第n项的值

样例输入

 复制

6
样例输出

 复制

8
提示
#include "stdio.h"
double a[100]; // 0号单元不用,全局变量如果没有初始化,则其值默认为0 
double f(int n){
	if (n<=2){
		 
	}
	else {
		
	}
}
int main(void){
	int n;
	scanf("%d",&n);
	printf("%.0lf\n",f(n));
}
#include "stdio.h"
 double a[100]; // 0号单元不用,全局变量如果没有初始化,则其值默认为0 
double f(int n){ 	
     if (n<=2){ 	
          return a[n]=1;
	  	} 	
     else { 
           if(a[n-1]==0){
              a[n-1]=f(n-1);
           }  
           if(a[n-2]==0){
              a[n-2]=f(n-2);
           } 	
           a[n]=a[n-1]+a[n-2];
           return a[n]; 
   	} 
}
int main(void){ 
  	int n; 
  	scanf("%d",&n); 	
   printf("%.0lf\n",f(n));
}

问题B: 游艇问题

题目描述

长江游艇俱乐部在长江上设置了n (n<=10)个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i 到游艇出租站j 之间的租金为r(i,j),1≤i<j≤n。要求设计一个算法,计算出从游艇出租站1 到游艇出租站n 所需的最少租金(使用动态规划法)。
要求:
第1行输入1个整数,表示有n个出租站点。
第2行输入n-1个整数,依次表示第1个站点到第i(1<i<=n)个站点的租金。
第3行输入n-2整数,依次表示第2个站点到第i(2<i<=n)个站点的租金。
...
第n行输入1整数,依次表示第n-1个站点到第i(n-1<i<=n)个站点的租金。
最后1行直接输出第1个出租点到第n个出租点的最小租金。

输入

4
2  4  6
2  5
1

输出

5

样例输入

 复制

5
2  4  6  8
1  2  3
1  2
3
样例输出

 复制

5
提示
#include <stdio.h>

int m[11][11]; // 假设下标为0的位置不存储有效数据

int f(int n) {
	
	int i,j,k,p;

	for(i=1; i<=n; i++) m[i][i]=0; // 给主对角线(第1条对解线)赋值
        ___________________________ 
        return m[1][n];
}

int main(void) {
	
	int i,j,n,result; 
	
	scanf("%d",&n);

	for(i =1; i < n; i++ )
		for(j =i+1; j <= n; j++ )
			scanf("%d",&m[i][j]);

	result=f(n);

	printf("%d\n",result);

	return 0;
}
算法设计思路:先写出计算m[i][j]值的递归式,然后根据递归式设计动态规划算法。
另外,如果本题不用动态规划,而是直接利用递归求解,则可参考下列程序代码(当问题规模比较大时,该代码的执行效率较低)
 
#include <stdio.h> int m[11][11]; // 假设下标为0的位置不存储有效数据 int f(int i, int j) { if(i==j) { return 0; } else { int min=m[i][j]; for(int k=i+1; k<j; k++) { _______________ } return min;
       }
}

int main(void) {

	int i,j,n,result;

	scanf("%d",&n);

	for(i =1; i < n; i++ )
		for(j =i+1; j <= n; j++ )
			scanf("%d",&m[i][j]);

	result=f(1,n);

	printf("%d\n",result);

	return 0;
}
#include <stdio.h>

int m[11][11]; // 假设下标为0的位置不存储有效数据

int f(int n) {
    int i, j, k;
    
    for(i = 1; i <= n; i++)
        m[i][i] = 0; // 给主对角线(第1条对解线)赋值

    for(j = 2; j <= n; j++) {
        for(i = 1; i <= n-j+1; i++) {
            int min = m[i][i+j-1]; // 初始化最小租金为当前的租金值
            for(k = i+1; k < i+j-1; k++) {
                int temp = m[i][k] + m[k][i+j-1];
                if(temp < min)
                    min = temp;
            }
            m[i][i+j-1] = min; // 更新租金值
        }
    }
    
    return m[1][n];
}

int main(void) {
    int i, j, n, result;
    
    scanf("%d", &n);
    
    for(i = 1; i < n; i++)
        for(j = i+1; j <= n; j++)
            scanf("%d", &m[i][j]);
    
    result = f(n);
    
    printf("%d\n", result);
    
    return 0;
}

问题C:矩阵连乘积

题目描述

给定n(1<=n<=9)个矩阵{A1, A2, …, An},其中Ai 与Ai +1是可乘的,i=1,…,n。要求找到一个计算次序使得求 n个矩阵连乘积A1, A2, …, An的数乘次数最少。 例如:如果有3个矩阵,第1个矩阵的行数和列数分别为1和2,第2个矩阵的行数和列数分别为2和3,第3个矩阵的行数和列数分别为3和4;如果先计算第1个矩阵和第2个矩阵的积(数乘次数为6=1*2*3),然后再计算刚得到的结果矩阵(1行3列)与第3个矩阵的积(数乘次数为12=1*3*4),总数乘的结果为18;如果先计算第2个矩阵和第3个矩阵的积(数乘次数为24=2*3*4),然后再计算第1个矩阵与刚得到的结果矩阵(2行4列)的积(数乘次数为8=1*2*4),总数乘的结果为32。因为3个矩阵的连乘积的计算方法只有上面两种情况,故最少的数乘次数为18。

输入

第一行输入一个整数,表示有n个矩阵相乘
第二行输入n+1个整数,分别表示n个矩阵的行和列数。注意,相邻两个矩阵相乘的条件是前者的列数与后者的行数相等,故输入数据时省略了一个整数。

输出

第一行输出最小的数乘次数。

样例输入

 复制

3
1 2 3 4
样例输出

 复制

18
提示
#include <stdio.h>


int m[11][11]; // 下标为0的单元“不存储”有效数据
int p[11]; // 注意:下标为0的单元“存储”有效数据

void MatrixChain(int p[],int n)
{
	for(int i=1;i<=n;i++) m[i][i]=0; //初始化第1条对角线(主对角线)		
			
	for(int r=2;r<=n;r++) //分别计算第r(此处没有使用变量p的原因是p已经作为形式参数了)条对角线上的值
	{
		for(int i=1;i<=n-r+1;i++)		
		{
			
		}
	}
}

int main(void)
{
	int i,n,result;
	
	scanf("%d",&n);		
	for(i=0;i<=n;i++) scanf("%d",&p[i]);
	  	
	MatrixChain(p,n);
	
	printf("%d\n",m[1][n]);
	
	return 0;
}
算法设计思路:先写出计算m[i][j]值的递归式(与租用游艇问题非常相似),然后根据递归式设计动态规划算法。
如果是4个矩阵,下标分别是1,2,3,4,5,则结果应该是什么?
#include <stdio.h>

int m[11][11]; // 假设下标为0的位置不存储有效数据
int p[11]; // 注意:下标为0的位置存储有效数据

void MatrixChain(int p[], int n) {
    int i, j, k, r;

    for (i = 1; i <= n; i++)
        m[i][i] = 0; // 初始化第1条对角线(主对角线)

    for (r = 2; r <= n; r++) {
        for (i = 1; i <= n - r + 1; i++) {
            int j = i + r - 1;
            m[i][j] = m[i][i] + m[i + 1][j] + p[i - 1] * p[i] * p[j];  // 初始化m[i][j]值
            for (k = i + 1; k < j; k++) {
                int temp = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                if (temp < m[i][j])
                    m[i][j] = temp;  // 更新m[i][j]值
            }
        }
    }
}

int main(void) {
    int i, n, result;

    scanf("%d", &n);
    for (i = 0; i <= n; i++)
        scanf("%d", &p[i]);

    MatrixChain(p, n);

    printf("%d\n", m[1][n]);

    return 0;
}

  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值