目录
1.斐波拉契数列问题
参见《从递归到DP——再看斐波拉契数列问题》https://blog.csdn.net/qq_41895747/article/details/103915415
科普斐波拉契数列:
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
AOJ题:
Fibonacci Number
Write a program which prints nn-th fibonacci number for a given integer nn. The nn-th fibonacci number is defined by the following recursive formula:
fib(n)=⎧⎩⎨⎪⎪1 1 fib(n−1)+fib(n−2)(n=0)(n=1)fib(n)={1 (n=0)1 (n=1)fib(n−1)+fib(n−2)
Input
An integer nn is given.
output
Print the nn-th fibonacci number in a line.
Constraints
0≤n≤440≤n≤44
Sample Input 1
3
Sample Output 1
3
//AOJ斐波拉契数列问题
#include <iostream>
using namespace std;
int dp[45];//根据题目里给定限制
int main(){
int n;
cin>>n;
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
cout<<dp[n]<<endl;
return 0;
}
2.被3整除的子序列问题
链接:https://ac.nowcoder.com/acm/problem/21302
来源:牛客网题目描述
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模输入描述:
输入一个字符串,由数字构成,长度小于等于50
输出描述:
输出一个整数
示例1
输入
132
输出
3
示例2
输入
9
输出
1
示例3
输入
333
输出
7
示例4
输入
123456
输出
23
示例5
输入
00
输出
3
备注:
n为长度 子任务1: n <= 5 子任务2: n <= 20 子任务3: 无限制
这题需要想到怎样取出DP的标准才行。
首先要知道被3整除的数,每一位的和一定能被3整除,这是常识。
试思考:怎样确定第i个数能被3整除?怎样确定前面有多少个能被3整除的位数?想明白了这题就是水题,想叉了这题就搞半天搞不了就像我一样……
首先一个数如果可以被3整除,那么这个数各位和一定可以被3整除。所以这个题应该是线性dp,我们定义dp[i][j]为前i个中整除3余数为j(只有0,1,2三个数)的个数,然后从头到尾线性dp一遍就可以了。
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int main(){
string t;
cin>>t;
int len=t.length();
int dp[55][3];
memset(dp,0,sizeof(dp));
int m=0;
dp[0][(t[0]-'0')%3]=1;
for(int i=1;i<len;i++){
m=(t[i]-'0')%3;
dp[i][m]=(dp[i][m]+1)%mod;
for(int j=0;j<3;j++){
dp[i][j]+=(dp[i-1][j]+dp[i-1][(j+3-m)%3])%mod;
}
//dp[i][m]=(dp[i][m]+1)%mod;
}
cout<<dp[len-1][0]%mod<<endl;
return 0;
}
3. 硬币问题
Coin Changing Problem
Find the minimum number of coins to make change for n cents using coins of denominations d1, d2,.., dm. The coins can be used any number of times.
Input
n m d1 d2 ... dm
Two integers n and m are given in the first line. The available denominations are given in the second line.
Output
Print the minimum number of coins in a line.
Constraints
- 1 ≤ n ≤ 50000
- 1 ≤ m ≤ 20
- 1 ≤ denomination ≤ 10000
- The denominations are all different and contain 1.
Sample Input 1
55 4 1 5 10 50
Sample Output 1
2
Sample Input 2
15 6 1 2 7 8 12 50
Sample Output 2
2
Sample Input 3
65 6 1 2 7 8 12 50
简单描述一下题意:
输入需要支付n元,共m种硬币,求支付n元的最少数目
看起来很像贪心,但是一些特殊的硬币组合贪心得不到最优解,反例很好举……
用DP解就对了,亮点是能将二维数组简化一维数组
//DP硬币问题
#include <iostream>
#include <algorithm>
using namespace std;
static const int INF=(1<<20);
static const int MMAX=20;
static const int NMAX=50000;
int main(){
int n,m;
int C[21];//表示第i个硬币的面值
int T[NMAX+1];//表示每一种面值的最优枚数
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>C[i];
//初始化
for(int i=1;i<=NMAX;i++)
T[i]=INF;
T[0]=0;
for(int i=1;i<=m;i++){
for(int j=0;j+C[i]<=n;j++){//j表示需要支付的金额
T[j+C[i]]=min(T[j+C[i]],T[j]+1);
}
}
cout<<T[n]<<endl;
return 0;
}
4.最长公共子序列
这位老哥写的非常好,不多说了
https://www.cnblogs.com/wkfvawl/p/9362287.html#_labelTop
//最长公共子序列问题
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const static int N=100;
int lcs(string X,string Y){
int c[N+1][N+1];
int m=X.size();
int n=Y.size();
int maxl=0;
//插入空格
X=' '+X;
Y=' '+Y;
//初始化
for(int i=1;i<=m;i++)
c[i][0]=0;
for(int j=1;j<=n;j++)
c[0][j]=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(X[i]==Y[j]){
c[i][j]=c[i-1][j-1]+1;
}else{
c[i][j]=max(c[i-1][j],c[i][j-1]);
}
maxl=max(maxl,c[i][j]);
}
}
return maxl;
}
int main(){
string s1,s2;
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>s1>>s2;
cout<<lcs(s1,s2)<<endl;
}
return 0;
}
参考:
https://www.cnblogs.com/hithongming/p/9229871.html