一、(what?)
二、(why?)
三、(how?)
四、典型例题分析:
例题1:神奇的兔子序列

输入:月数
输出:兔子数
思路:



代码1(函数递归):
- #include
- using namespace std;
-
- int fib(int n)
- {
- if(n < 1)
- return -1;
- else if(n == 1|| n == 2)
- return 1;
- else
- return fib(n-1)+fib(n-2);
- }
-
- int main()
- {
- int n;
- cin>>n;
- cout<<fib(n);
- return 0;
- }
代码2(数组递归):
- #include
- 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
- 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
- {
- cout<
- }
- cout<
- }
- }
-
- return 0;
- }
显示所有子串:
求其中一个子串的数组:
- #include
- 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
- {
- str1[len1]+=s[q];
- }
- len1++;
- }
- }
- for(int k=0;k
- {
- cout<
- }
- return 0;
- }
输出:

题解代码:
- #include
- #include
- 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
length()) - {
- s[i]=st1[i];
- i++;
- }
- while(j
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
- {
- str1[len1]+=s[q];
- }
- len1++;
- }
- }
- /*
- for(int k=0;k
- {
- cout<
- } */
- //存入第二个子串数组
- for(int k=0;k<=6;k++)
- {
- for(int i=k;i<=6;i++)
- {
- for(int q=k;q
- {
- str2[len2]+=ss[q];
- }
- len2++;
- }
- }
- /*
- for(int k=0;k
- {
- cout<
- }
- */
- int temp=0,max=-1000;
- string answer;
- for(int i=0;i
- {
- string strr1=str1[i];
- for(int j=0;j
- {
- if(str2[j]==strr1)
- {
- temp=strr1.length();
- if(temp>=max)
- {
- max=temp;
- answer=strr1;
- }
- }
- }
- }
- cout<
- 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开始
- { //如果当前字符相同,则公共子序列的长度为该字符前的最长公共序列+1
- c[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<
-1]; - }
- else if(b[i][j]==2)
- print(I,j-1);
- else print(i-1,j);
- }
代码:
- #include
- #include
- 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,编辑距离初始化为i
- d[i][0]= i;
- for(int j=0;j<=len2;j++) //当第一个串长度为0,编辑距离初始化为j
- d[0][j]=j;
- for(int i=1;i <=len1;i++) //遍历两个字符串
- {
- for(int j=1;j<=len2;j++)
- {
- int diff;//判断str[i]是否等于str2[j],相等为0,不相等为1
- if(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);//再取最小值,
- //相当于三者取最小值d[i-1][j] + 1, d[i][j-1] + 1,d[i-1][j-1] + diff
- }
- }
- return d[len1][len2];
- }
完整代码:
- #include
- #include
- 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//返回较小值
- }
-
- 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,编辑距离初始化为j
- d[0][j] = j;
- }
- //遍历两个字符串
- for(int i=1;i<=len1;i++)
- {
- for(int j=1; j<=len2;j++)
- {
- int diff;//判断字符是否相等,相等不需要编辑+0,不相等+1
- if(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<
- }
- cout<
- }
- 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
//记录每一个小规模内的最优解 - {
- int temp;
- temp=m[i][k]+m[k][j];
- if(temp
- {
- m[i][j]=temp;
- s[i][j]=k;
- }
- }
- }
- }
- }

- void print(int i,int j)
- {
- if(s[i][j]==0 )
- {
- cout << "--"<
- return ;
- }
- print(i,s[i][j]);
- print(s[i][j],j);
- }
完整代码:
- //program 4-3
- #include
- 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
//记录每一个小规模内的最优解 - {
- int temp;
- temp=m[i][k]+m[k][j];
- if(temp
- {
- m[i][j]=temp;
- s[i][j]=k;
- }
- }
- }
- }
- }
- void print(int i,int j)
- {
- if(s[i][j]==0 )
- {
- cout << "--"<
- 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 << "花费的最少租金为:" <
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
- #include
- #include
- 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
//当物品的重量大于购物车的容量,则不放此物品 - 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<<"装入购物车的最大价值为:"<

- //逆向构造最优解
- j=W;
- for(i=n;i>0;i--)
- if(c[i][j]>c[i-1][j])
- {
- x[i]=1;
- j-=w[i];
- }
- else
- x[i]=0;
- cout<<"装入购物车的物品为:";
- for(i=1;i<=n;i++)
- if(x[i]==1)
- cout<" ";
完整代码:
- //program 4-7
- #include
- #include
- 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列为0
- c[i][0]=0;
- for(j=0;j<=W;j++) //初始化第0行为0
- c[0][j]=0;
- for(i=1;i<= n;i++) //计算c[i][j]
- for(j=1;j<=W;j++)
- if(j
//当物品的重量大于购物车的容量,则不放此物品 - 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<<"装入购物车的最大价值为:"<
- //逆向构造最优解
- j=W;
- for(i=n;i>0;i--)
- if(c[i][j]>c[i-1][j])
- {
- x[i]=1;
- j-=w[i];
- }
- else
- x[i]=0;
- cout<<"装入购物车的物品为:";
- for(i=1;i<=n;i++)
- if(x[i]==1)
- cout<" ";
- return 0;
- }
输入输出:

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

-
相关阅读:
【m_listCtrl !=NULL有多个运算符与操作数匹配】2023/9/21 上午11:03:44
C2基础设施威胁情报对抗策略
GC如何判断对象可以被回收
pycharm基本使用(常用快捷键)
2024国际生物发酵展畅想未来-势拓伺服科技
spring cloud alibaba nacos搭建最小可运行微服务
成员变量为动态数据时不可轻易使用
SQL存储过程详解
【新笔记本环境配置】win10下 Anaconda+Vscode+MobaXterm安装
下列程序的运行结果是 #include <stdio.h> void main() { int x = 10, y = 20, z = 30;
-
原文地址:https://blog.csdn.net/qq_51701007/article/details/122666147