经典DP问题总结(1)——硬币问题、最长公共子序列、斐波拉契数列、整除子序列问题

目录

1.斐波拉契数列问题

 2.被3整除的子序列问题

3. 硬币问题

4.最长公共子序列

参考:


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

Source: https://onlinejudge.u-aizu.ac.jp/problems/DPL_1_A

 简单描述一下题意:

输入需要支付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

https://ac.nowcoder.com/acm/problem/blogs/21302

https://www.cnblogs.com/fsmly/p/10228767.html

发布了228 篇原创文章 · 获赞 76 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_41895747/article/details/103931625