//动态规划
//记忆化搜索-
//递归自上而下的解决问题:我们没有从一个基本的问题开始解决,
//而是假设基本的问题已经被解决了,如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)
- d[s]表示总数为s时所需的硬币数,
- d[ s - v[i] ] 表示用总和为s-v[i]时,所需的硬币数,d[s-v[i]] +1表示使得面值恰好为s的硬币数
- 那么,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
版权声明:本文为博主原创文章,转载请附上博文链接!