动 态 规 划

一、(what?)

二、(why?)

三、(how?)

四、典型例题分析:

例题1:神奇的兔子序列

输入:月数

输出:兔子数

思路:

代码1(函数递归):

#include<iostream>
using namespace std;int fib(int n)
{if(n < 1)return -1;else if(n == 1|| n == 2)return 1;elsereturn fib(n-1)+fib(n-2);
}int main()
{int n;cin>>n;cout<<fib(n);return 0;
} 

代码2(数组递归):

#include<iostream>
using namespace std;int fib(int n)
{if(n < 1) return -1;int F[n+1];F[1] = 1, F[2] = 1;for(int i = 3; i <= n; i++)F[i] = F[i-1]+F[i-2];return F[n];
}int main()
{int n;cin>>n;cout<<fib(n);return 0;
} 

例题2:孩子有多像爸爸——最长公共子序列

 暴力搜索

举个简单的暴力搜索的

#include<iostream>
using namespace std;
int main()
{char s[7]={'A','B','C','B','A','D','B'};for(int k=0;k<=7;k++){for(int i=k;i<=7;i++){for(int j=k;j<i;j++){cout<<s[j];}cout<<endl;}	}return 0;} 

 显示所有子串:

 求其中一个子串的数组:

#include<iostream>
using namespace std;
int main()
{char s[7] = {'A','B','C','B','A','D','B'};//char ss[6] = {'B','C','B','A','A','C'};string str1[100],str2[100];int len1=0,len2=0;for(int k=0;k<=7;k++){for(int i=k;i<=7;i++){for(int q=k;q<i;q++){str1[len1]+=s[q];}len1++;}	}	for(int k=0;k<len1;k++){cout<<str1[k]<<endl;}	return 0;} 

 输出:

题解代码:

#include<iostream>
#include<string>
using namespace std;const int MAX=1000;char s[MAX],ss[MAX];string str1[MAX],str2[MAX];int len1=0,len2=0;int main()
{//char s[7] = {'A','B','C','B','A','D','B'};//char ss[6] = {'B','C','B','A','A','C'};//string str1[100],str2[100];//int len1=0,len2=0;string st1,st2;cin>>st1>>st2;int i=0,j=0;while(i<st1.length()){s[i]=st1[i];i++;}while(j<st2.length()){ss[j]=st2[j];j++;}//存入第一个子串数组 for(int k=0;k<=7;k++){for(int i=k;i<=7;i++){for(int q=k;q<i;q++){str1[len1]+=s[q];}len1++;}	}/*	for(int k=0;k<len1;k++){cout<<str1[k]<<endl;}	*///存入第二个子串数组for(int k=0;k<=6;k++){for(int i=k;i<=6;i++){for(int q=k;q<i;q++){str2[len2]+=ss[q];}len2++;}	}	/*	for(int k=0;k<len2;k++){cout<<str2[k]<<endl;}	 */int temp=0,max=-1000;string answer;for(int i=0;i<len1;i++){string strr1=str1[i];for(int j=0;j<len2;j++){if(str2[j]==strr1){temp=strr1.length();if(temp>=max){max=temp;answer=strr1;}}}	} cout<<answer<<endl<<max;	return 0;} 

结果:

*注:这并不是例题的解法,只是对暴力搜索举个例子,二者并无关联!

原理题的条件子串是从父亲的基因中取一些值并非一定连续!!!

 下面,用动态规划算法解决此问题

算法设计:

图解算法:

 

 

 

 

 

伪代码:

Void LCSL()
{int I,j;for(I = 1;I <= len1;i++)    //控制s1序列for(j = 1;j <= len2;j++)  //控制s2序列{if(s1[i-1]==s2[j-1])    //字符下标从0开始{   //如果当前字符相同,则公共子序列的长度为该字符前的最长公共序列+1c[i][j] = c[i-1][j-1]+1;b[i][j] = 1;}else{if(c[i][j-1]>=c[i-1][j]) //两者找最大值,并记录最优策略来源{c[i][j] = c[i][j-1];b[i][j] = 2;}else{c[i][j] = c[i-1][j];b[i][j] = 3;}}}
}

Void print(int I, int j)//根据记录下来的信息构造最长公共子序列(从b[i][j]开始递推)
{if(i==0 || j==0) return;if(b[i][j]==1){print(i-1,j-1);cout<<s1[i-1];}else if(b[i][j]==2)print(I,j-1);else print(i-1,j);
}

代码:

#include<iostream>
#include<string>
using namespace std;
const int N = 1002;//数组最大长度 
int c[N][N], b[N][N];//c:公共子序列长度。b:答案路径
char s1[N], s2[N];
int len1, len2;//动态规划查询最大子序列函数 
void LCSL()
{int i, j;for (i = 1; i <= len1; i++)//控制s1序列{for (j = 1; j <= len2; j++)//控制s2序列{//动态规划开始if (s1[i - 1] == s2[j - 1])//字符下标从0开始 {//如果字符相同,公共子序列的长度为该字符前的最长公共子序列(左上角)+1 c[i][j] = c[i - 1][j - 1] + 1;b[i][j] = 1;//此情况标记为1 }else{//如果字符不相等的子序列长度 if (c[i][j - 1] >= c[i - 1][j]){//如果上面的大于左面,子序列长度为上值 c[i][j] = c[i][j - 1];b[i][j] = 2;//取上值为2 }else{//如果左大于上,取左值 c[i][j] = c[i - 1][j];b[i][j] = 3;//取左值为3 }}}}for (i = 0; i <= len1; i++){for(j = 0; j <= len2; j++){cout << c[i][j];}cout << endl;}
}//输出最优路径的函数(因为是函数递归,所以经过倒退能得到正序路径) 
void print(int i, int j)//从b[i][j]开始递推 
{if (i == 0 || j == 0) return;//如果有一个序列递归完了就结束递归if (b[i][j] == 1){//说明此时s1[i-1]=s2[j-1],b[i][j]的值来自c左上角 print(i - 1, j - 1);//递归去左上角 cout << s1[i - 1];}else if (b[i][j] == 2){//s1[i-1]与s2[j-1]不等,b[i][j]值来自c上 print(i, j - 1);}else{//字符不等取值来自左 print(i - 1, j);}
}int main()
{int i, j;cout << "输入字符串s1:" << endl;cin >> s1;cout << "输入字符串s2:" << endl;cin >> s2;len1 = strlen(s1);//求char型数组的长度len2 = strlen(s2);for (i = 0; i <= len1; i++){c[i][0] = 0;//初始化第一行	}for (j = 0; j <= len2; j++){c[0][j] = 0;//初始化第一列	}LCSL();//求最长子序列cout << "最长子序列长度为:" << c[len1][len2] << endl;cout << "最长公共子序列是:";print(len1, len2);return 0;
}

输出: 

例题3:DNA基因鉴定——编辑距离

 算法设计:

算法图解:

 

 

伪代码:

int editdistance(char *str1, char *str2)
{int len1 = strlen(str1);      //计算字符串长度int len2 = strlen(str2); for(int i=0;i<=len1;i++)      //当第二个串长度为0,编辑距离初始化为id[i][0]= i;for(int j=0;j<=len2;j++)      //当第一个串长度为0,编辑距离初始化为jd[0][j]=j;for(int i=1;i <=len1;i++)     //遍历两个字符串{for(int j=1;j<=len2;j++){int diff;//判断str[i]是否等于str2[j],相等为0,不相等为1if(str1[i-1] == str2[j-1]) //相等diff = 0 ;elsediff = 1 ;int temp = min(d[i-1][j] + 1, d[i][j-1] + 1);//先两者取最小值d[i][j] = min(temp, d[i-1][j-1] + diff);//再取最小值,//相当于三者取最小值d[i-1][j] + 1, d[i][j-1] + 1,d[i-1][j-1] + diff}}return d[len1][len2];
}

 完整代码:

#include<iostream>
#include<string>
using namespace std;
const int N = 100;
char str1[N],str2[N];
int d[N][N];//d[i][j]表示的str1前i个字符的str2前j个字符的编辑距离int StrLen(char *s)//求字符串长度 
{int i=0;while(s[i]!='\0'){i++;	}	return i;
} int min(int a,int b)
{return a<b?a:b; //返回较小值 
}int editdistance(char *str1,char *str2)
{int len1=StrLen(str1);int len2=StrLen(str2);	//初始化for(int i=0;i<=len1;i++){//第二个串长度为0,编辑距离初始化为i d[i][0]	= i;} for(int j=0;j<=len2;j++){//第二个串长度为0,编辑距离初始化为jd[0][j]	= j;}//遍历两个字符串 for(int i=1;i<=len1;i++){for(int j=1; j<=len2;j++){int diff;//判断字符是否相等,相等不需要编辑+0,不相等+1if(str1[i-1] == str2[j-1]){diff=0;}else{diff=1;	} int temp=min(d[i-1][j]+1,d[i][j-1]+1);d[i][j] = min(temp,d[i-1][j-1]+diff);//连去两次两个求最小值等价于三个求最小值 }}for(int i=0;i<=len1;i++){for(int j=0;j<=len2;j++){cout<<d[i][j];}cout<<endl;}return d[len1][len2]; 
} 
int main()
{cin>>str1>>str2;cout<<editdistance(str1,str2);return 0;
}

 输入输出:

例题4:长江一日游——游艇租赁

算法设计: 

 算法图解:

伪代码:

void rent()
{int i,j,k,d;for(d=3;d<=n;d++) //将问题分为小规模d{for(i=1;i<=n-d+1;i++){j=i+d-1;for(k=i+1;k<j;k++)  //记录每一个小规模内的最优解{int temp;temp=m[i][k]+m[k][j];if(temp<m[i][j]){m[i][j]=temp;s[i][j]=k;}}}}
}

 

void print(int i,int j)
{if(s[i][j]==0 ){cout << "--"<<j;return ;}print(i,s[i][j]);print(s[i][j],j);
}

 完整代码:

//program 4-3
#include<iostream>
using namespace std;
const int ms = 1000;
int r[ms][ms],m[ms][ms],s[ms][ms];    //i到j站的租金
int n;            //共有n个站点
void rent()
{int i,j,k,d;for(d=3;d<=n;d++) //将问题分为小规模为d{for(i=1;i<=n-d+1;i++){j=i+d-1;for(k=i+1;k<j;k++)  //记录每一个小规模内的最优解{int temp;temp=m[i][k]+m[k][j];if(temp<m[i][j]){m[i][j]=temp;s[i][j]=k;}}}}
}
void print(int i,int j)
{if(s[i][j]==0 ){cout << "--"<<j;return ;}print(i,s[i][j]);print(s[i][j],j);
}
int main()
{int i,j;cout << "请输入站点的个数 n:";cin >> n;cout << "请依次输入各站点之间的租金:";for(i=1;i<=n;i++)for(j=i+1;j<=n;++j){cin>>r[i][j];m[i][j]=r[i][j];}rent();cout << "花费的最少租金为:" <<m[1][n] << endl;cout <<"最少租金经过的站点:"<<1;print(1,n);return 0;
}

输入输出:

例题5:快速计算——矩阵连乘

 算法设计:

图解算法:

 伪代码:

void print(int i,int j)
{if( i == j ){cout <<"A[" << i << "]";return ;}cout << "(";print(i,s[i][j]);print(s[i][j]+1,j);cout << ")";
}

 完整代码:

//program 4-4
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int msize = 100;
int p[msize];
int m[msize][msize],s[msize][msize];
int n;
void matrixchain()
{int i,j,r,k;memset(m,0,sizeof(m));memset(s,0,sizeof(s));for(r = 2; r <= n; r++)          //不同规模的子问题{for(i = 1; i <= n-r+1; i++){j = i + r - 1;m[i][j] = m[i+1][j] + p[i-1] * p[i] * p[j];  //决策为k=i的乘法次数s[i][j] = i;            //子问题的最优策略是i;for(k = i+1; k < j; k++) //对从i到j的所有决策,求最优值,记录最优策略{int t = m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j];if(t < m[i][j]){m[i][j] = t;s[i][j] = k;}}}}
}
void print(int i,int j)
{if( i == j ){cout <<"A[" << i << "]";return ;}cout << "(";print(i,s[i][j]);print(s[i][j]+1,j);cout << ")";
}
int main()
{cout << "请输入矩阵的个数 n:";cin >> n;int i ,j;cout << "请依次输入每个矩阵的行数和最后一个矩阵的列数:";for (i = 0; i <= n; i++ )cin >> p[i];matrixchain();print(1,n);cout << endl;cout << "最小计算量的值为:" << m[1][n] << endl;
}

 输入输出:

例题6:切呀切披萨——最优三角剖分

例题7:小石子游戏——石子合并

例题8:大卖场购物车——0-1背包问题

 算法设计:

 图解算法:

伪代码:

for(i=1;i<= n;i++)           //计算c[i][j]for(j=1;j<=W;j++)if(j<w[i])    //当物品的重量大于购物车的容量,则不放此物品c[i][j] = c[i-1][j];else          //否则比较此物品放与不放是否能使得购物车内的价值最大c[i][j] = max(c[i-1][j],c[i-1][j-w[i]] + v[i]);cout<<"装入购物车的最大价值为:"<<c[n][W]<<endl;

 

//逆向构造最优解
j=W;
for(i=n;i>0;i--)if(c[i][j]>c[i-1][j]){x[i]=1;j-=w[i];}elsex[i]=0;
cout<<"装入购物车的物品为:";
for(i=1;i<=n;i++)if(x[i]==1)cout<<i<<"  ";

 完整代码:

//program 4-7
#include <iostream>
#include<cstring>
using namespace std;
#define maxn 10005
#define M 105
int c[M][maxn];         //c[i][j] 表示前i个物品放入容量为j购物车获得的最大价值
int w[M],v[M];          //w[i] 表示第i个物品的重量,v[i] 表示第i个物品的价值
int x[M];               //x[i]表示第i个物品是否放入购物车
int main(){int i,j,n,W;       //n表示n个物品,W表示购物车的容量cout << "请输入物品的个数n:";cin >> n;cout << "请输入购物车的容量W:";cin >> W;cout << "请依次输入每个物品的重量w和价值v,用空格分开:";for(i=1;i<=n;i++)cin>>w[i]>>v[i];for(i=0;i<=n;i++)  //初始化第0列为0c[i][0]=0;for(j=0;j<=W;j++)  //初始化第0行为0c[0][j]=0;for(i=1;i<= n;i++) //计算c[i][j]for(j=1;j<=W;j++)if(j<w[i])  //当物品的重量大于购物车的容量,则不放此物品c[i][j] = c[i-1][j];else    //否则比较此物品放与不放是否能使得购物车内的价值最大c[i][j] = max(c[i-1][j],c[i-1][j-w[i]] + v[i]);cout<<"装入购物车的最大价值为:"<<c[n][W]<<endl;//逆向构造最优解j=W;for(i=n;i>0;i--)if(c[i][j]>c[i-1][j]){x[i]=1;j-=w[i];}elsex[i]=0;cout<<"装入购物车的物品为:";for(i=1;i<=n;i++)if(x[i]==1)cout<<i<<"  ";return 0;
}

输入输出:

例题9:快速定位——最优二叉搜索

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/190251.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SecureCRT的“New line mode“

New line mode选中与不选中啥区别 在SecureCRT中&#xff0c;"New line mode"是一个关键配置项&#xff0c;主要用于解决不同操作系统之间的换行问题。当不选中"New line mode"时&#xff0c;SecureCRT会将接收到的数据按照原样发送&#xff0c;不会对数据…

基于Vue+SpringBoot的高校学生管理系统 开源项目

项目编号&#xff1a; S 029 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S029&#xff0c;文末获取源码。} 项目编号&#xff1a;S029&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生管理模块2.2 学院课程模块2.3 学…

回 溯 法

一、&#xff08;what&#xff1f;&#xff09; 二、&#xff08;why&#xff1f;&#xff09; 三、&#xff08;how&#xff1f;&#xff09; 四、典型例题分析&#xff1a; 例题1&#xff1a;大卖场购物车2——0-1背包问题 问题分析&#xff1a; 算法设计&#xff1a; 图…

for,while,do-while,死循环,嵌套循环,跳转关键字,随机数

1.for循环 public class ForDemo1 {public static void main(String[] args) {for (int i 0; i < 5; i) {System.out.println("HelloWorld");}System.out.println("--------------------------------------------");for (int i 1; i <10 ; i) {Sy…

反激变压器计算方法_笔记

反激变压器计算方法_笔记 匝数比原边电感选定磁芯线圈匝数线径 原视频链接 匝数比 5V 是想要得到的输出电压 0.7V为二极管导通的压降 185Vx根号2是有效值 最大占空比取0.4。得出最小匝数为30。 更改某些值可能得出来的匝数比就不一定是30了&#xff0c; 这其实也是反激变压器…

PS学习笔记——新建文档/修改文档

文章目录 新建文档文档属性像素/分辨率颜色模式背景内容高级选项存储预设 修改文档 新建文档 方法一&#xff1a;ctrlN快捷键可直接打开新建文档界面 方法二&#xff1a;点击菜单栏中 文件->新建&#xff0c;即可打开新建文档界面 文档参数可按需调节(标题可以提前设定或者…

分布式服务与分布式框架

分布式副武其实就是根据某个粒度&#xff0c;将服务拆分&#xff0c;而分布式框架就是将这些服务协调&#xff0c;管理起来。分布式框架&#xff0c;我认为服务调用是他的基础能力&#xff0c;该能力是所有分布式框架的基础能力&#xff0c;其次是服务注册与发现。 在这个维度…

Mac M1 M1 pro安装 protobuf 2.5.0

因为项目中的protobuf是2.5.0版本&#xff0c;但是旧版本的protobuf 不支持M1&#xff0c;此时需要修改源码重新编译 操作步骤&#xff1a; 从git上面下载对应版本的protobuf&#xff0c;地址&#xff1a;Release Protocol Buffers v2.5.0 protocolbuffers/protobuf GitHub…

Leetcode 【2342. 数位和相等数对的最大和】

给你一个下标从 0 开始的数组 nums &#xff0c;数组中的元素都是 正 整数。请你选出两个下标 i 和 j&#xff08;i ! j&#xff09;&#xff0c;且 nums[i] 的数位和 与 nums[j] 的数位和相等。 请你找出所有满足条件的下标 i 和 j &#xff0c;找出并返回 nums[i] nums[j]…

【Linux】进程间是这样通信的--管道篇

TOC 目录 进程间通信的介绍 进程间通信的概念 进程间通信的目的 进程间通信的本质 进程间通信的分类 管道 什么是管道 匿名管道 pipe函数 匿名管道使用步骤 管道读写规则 管道的特点 1、管道内部自带同步与互斥机制 2、管道的生命周期随进程 3、管道提供的是流式…

DevSeo Studio设置中文界面

安装好DevSeo Studio后默认打开是欢迎页。 左下角Configure点击展开&#xff0c;选择plugins 弹出页面选择“installed”,然后输入chinese,默认是关闭的&#xff0c;点击enable将它启用&#xff0c;然后点击OK。 弹出页面点击“restart”重启即可。

face_recognition:高准确率、简单易用的人脸识别库 | 开源日报 No.79

ageitgey/face_recognition Stars: 49.8k License: MIT 这个项目是一个使用 Python 编写的人脸识别库&#xff0c;可以从图片中识别和操作人脸。它基于 dlib 开发&#xff0c;并采用深度学习技术构建了最先进的人脸识别模型&#xff0c;在 Labeled Faces in the Wild 数据集上…