动态规划入门

//动态规划
//记忆化搜索-
//递归自上而下的解决问题:我们没有从一个基本的问题开始解决,
//而是假设基本的问题已经被解决了,如f(n) = f(n-1) + f(n-2),
//我们假设f(n-1)和f(n-2)已经解决了,有答案了,那么f(n)也就随之有了答案了。
//一般能有自上而下解决问题的一定能自下而上解决。比如看下面的自上而下,再看看后面的自下而上
//大多数动态规划问题本质其实为递归问题:递归的解决重叠子问题
//1)记忆化搜索,从上到下;2)动态规划,自底向上;两者本质上是相同的。但是从上到下的方式更容易思考
//自上而下

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#define N 40
int fibcount = 0;
long long am[N];
//自上而下
int fibsx(int n){
	fibcount++;
	if(n <= 0){
		// am[0] = 0;
		return 0;
	}
	if(n == 1){
		// am[0] = 1;
		return 1;
	}
	if(am[n] == -1){
		am[n] = fibsx(n-1)+fibsx(n-2);
	}
	return am[n];
}

//自下而上
//没有函数调用,没有函数栈的浪费,am每一项只是访问一次,而上面的不止一次。
int fibxs(int n){
	int i = 0;
	am[0]=0;
	am[1]=1;
	for(i=2;i<=n;i++){
		am[i] = am[i-1]+am[i-2];
	}
	return am[n];
}
int main(){
	// int n = N;
	int i = 0;
	time_t t1,t2;
	for(i=0;i<=N;i++){
		am[i] = -1;
		printf("%lld ",am[i]);
	}

	printf("\n\n\n");

	time_t startTime = clock();
	// time(&t1);
	int res =fibsx(N);
	// time(&t2);
	time_t endTime = clock();

	printf("fib is %d 。",res);
	printf("time start,end is %f\n",difftime(endTime,startTime)/CLOCKS_PER_SEC);
	// printf("time t1 t2 is %f\n",difftime(t2,t1));
	printf("fib count is %d\n",fibcount);
	for(i=0;i<=N;i++){
		printf("%lld ",am[i]);
	}
	return 0;
}

 

看了雷霄骅的故事,为之深表惋惜,一位为科研埋头奉献发光发热的人,这件事也促使我开通博客,来记录自己一点学习的过程。

最近在看动态规划的内容,看了硬币找零问题,是一个很好的对动态规划算法入门的问题。

问题描述如下:


有n种硬币,面值分别为v1,v2,v3,…,vn,每种都有无限多个,给定非零整数s,可以选用多个硬币,使得面值之和恰好为s。输出所需硬币的最小值和最大值。


动态规划关键是找出状态转移方程, 然后依据状态转移方程用递归或递推的方法来实现问题的求解。该问题中硬币数目是不限的,状态方程应重点考虑被找零的数目和硬币面值之间的关系,问题中需要得出所需硬币的最小值和最大值,我们用数组d来表示当前给定的s所需的最大数目和最少数目,状态方程即为:

d[s]=max{d[s-v[i]]+1, d[s]}      (1)

d[s]=min{d[s-v[i]]+1, d[s]}      (2)
  1. d[s]表示总数为s时所需的硬币数,
  2. d[ s - v[i] ]  表示用总和为s-v[i]时,所需的硬币数,d[s-v[i]] +1表示使得面值恰好为s的硬币数
  3.  那么,d[s]=max{d[s-v[i]]+1, d[s]}表示递推(选择)当前方案所需的硬币数(d[s])与方案(d[s-v[i]]+1)的较大者。

下面给出分别用递归和递推的方法实现的求解:

1. 递归法

求解最大值   

 void df_max(int s, int v[], int n, int d[])
 {
    if(s == 0)
        return ;
    if(s > 0)
    {
        for(int i =0; i<n; i++)
        {
            if(s >= v[i])
            {
                if(d[s -v[i]] == 0)
                    df_max(s-v[i], v, n, d);
                d[s] = d[s] < (d[s - v[i]] + 1) ? (d[s - v[i]] + 1) : d[s];
            }
        }
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    int s=10;
    int v[] = {1,2,5};
    int n = sizeof(v)/sizeof(int);
    int *d = new int[s+1];
    memset(d, 0, sizeof(int)*(s+1));
    d[0] = 0;
    df_max(s, v, n, d);
    cout<<"The max result: "<<d[s]<<endl<<endl;

    for(int i=0; i<=s; i++)
    {
        cout<<d[i]<<' ';
    }
    return 0;
}

递归法求解最小值
   

void df(int s, int v[], int n, int d[])
{
 
    if(s == 0)
        return ;
    if(s > 0)
    {
        for(int i =0; i<n; i++)
        {
            if(s >= v[i])
            {
                if(d[s -v[i]] != 0)
                    df(s-v[i], v, n, d);
                d[s] = d[s] > (d[s - v[i]] + 1) ? (d[s - v[i]] + 1) : d[s];
            }
        }
    }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    int s=10;
    int v[] = {1,2,5};
    int n = sizeof(v)/sizeof(int);
    int *d = new int[s+1];
    memset(d, 1, sizeof(int)*(s+1));
    d[0] = 0;
    df(s, v, n, d);
    cout<<"The min result: "<<d[s]<<endl;

    for(int i=0; i<=s; i++)
    {
        cout<<d[i]<<' ';
    }
    return 0;
}


2. 递推法

    void c_max_min(int s, int v[], int n, int max[], int min[])
    {
        for(int i=1; i <= s; i++)
            for(int j = 0; j < n; j++)
            {
                if (i >= v[j])
                {
                    max[i] = max[i] < (max[i-v[j]]+1) ? (max[i-v[j]]+1) : max[i];
                    min[i] = min[i] > (min[i-v[j]]+1) ? (min[i-v[j]]+1) : min[i];
                }
            }
    }
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        int s=10;
        int v[] = {1,2,5};
        int n = sizeof(v)/sizeof(int);
        int *max = new int[s+1];
        int *min = new int[s+1];
        memset(max, 0, sizeof(int)*(s+1));

            //注意这里初始值的设定,s为1时需要一枚硬币
        memset(min, 1, sizeof(int)*(s+1));
        min[0] = 0;
        c_max_min(s, v, n, max, min);
        cout<< max[s] << ' ' << min[s] <<endl;
        return 0;
    }

参看书目:《算法竞赛入门经典》 刘汝佳 著
---------------------  
作者:古巴与八股  
来源:CSDN  
原文:https://blog.csdn.net/xuedingkai/article/details/52425321  
版权声明:本文为博主原创文章,转载请附上博文链接!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值