1.找零钱
int coinChange(int* coins, int coinsSize, int amount) {
int dp[amount + 1];
memset(dp,-1,sizeof(dp));
dp[0] = 0;
for (int i = 1; i <= amount; i++)
for (int j = 0; j < coinsSize; j++)
if (coins[j] <= i && dp[i - coins[j]] != -1)
if (dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1)
dp[i] = dp[i - coins[j]] + 1;
return dp[amount];
}
2.不同路径
int uniquePaths(int m, int n) {
int dp[m+1][n+1];
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
if(i==1||j==1)
dp[i][j]=1;
else
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
return dp[m][n];
}
3.最小路径和
int minPathSum(int** grid, int gridSize, int* gridColSize) {
int m=gridSize,n=gridColSize[0];
int dp[m][n];
memset(dp,0,sizeof(dp));
dp[0][0]=grid[0][0];
for(int i=1;i<m;i++)
dp[i][0]=dp[i-1][0]+grid[i][0];
for(int j=1;j<n;j++)
dp[0][j]=dp[0][j-1]+grid[0][j];
for(int i=1;i<m;i++)
for(int j=1;j<n;j++)
dp[i][j]=fmin(dp[i-1][j],dp[i][j-1])+grid[i][j];
return dp[m-1][n-1];
}
4.有奖问答
#include <iostream>
using namespace std;
int ans=0;
int dp[31][10];//dp[i][j]代表回答了i道题目时得到了j*10的分数的 总方案数
int main(){
dp[0][0] = 1;//初始化起点,起点就表示一个方案数
for(int i = 1;i<=30;i++)
for(int j = 0;j<=9;j++)
if(j==0)//得到零分,说明这一题答错了,那么方案数量就是上一题的所有方案之和,上一题多少分都不影响当前题,因为一旦答错,分数归零。
for(int k = 0;k<=9;k++)
dp[i][j] += dp[i-1][k];
else//答对了,那么说明这个方案必须承接上一次答对的方案数,上一题必须是当前分数-10,即j-1道题。
dp[i][j] = dp[i-1][j-1];
for(int i = 0;i<=30;i++)
ans+=dp[i][7];//记录所有答对7次的方案数
cout<<ans;
return 0;answerquest
}
5.字符串转换
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string s,t;
int transform(){
int l1=s.length(),l2=t.length();
int dp[l1+1][l2+1];
for(int i=0;i<l1;i++)
dp[i][0]=i;
for(int j=0;j<l2;j++)
dp[0][j]=j;
for(int i=1;i<=l1;i++)
for(int j=1;j<=l2;j++){
if(s[i-1]==t[j-1])
dp[i][j]=dp[i-1][j-1];
else
dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
}
return dp[l1][l2];
}
int main()
{
// 请在此输入您的代码
cin>>s>>t;
printf("%d",transform());
return 0;
}
动态规划浅析——记一道困难的字符串操作数问题 - 知乎 (zhihu.com),这个文章写的很不错,可以看看。
6.完全背包问题
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,v;
struct obj{
int v;//体积
int c;//价值
};
int packet(obj o[]){
int dp[n+1][v+1];//选第i个物品且体积为j时的价值
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=0;j<=v;j++){
dp[i][j]=dp[i-1][j];
for(int k=0;k*o[i].v<=j;k++){
dp[i][j]=max(dp[i][j],dp[i-1][j-k*o[i].v]+k*o[i].c);
}
}
}
return dp[n][v];
}
int main()
{
// 请在此输入您的代码
scanf("%d%d",&n,&v);
obj o[n+1];
o[0].v=0,o[0].c=0;
for(int i=1;i<=n;i++)
scanf("%d%d",&o[i].v,&o[i].c);
printf("%d",packet(o));
return 0;
}
7.松散子序列
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
string s;
inline int value(char a){
return a-'a'+1;
}
int SubSeq(){
int len=s.length();
int dp[len];
memset(dp,0,sizeof(dp));
dp[0]=value(s[0]);
dp[1]=max(dp[0],value(s[1]));
for(int i=2;i<len;i++)
dp[i]=max(dp[i-1],dp[i-2]+value(s[i]));
return dp[len-1];
}
int main()
{
// 请在此输入您的代码
cin>>s;
cout<<SubSeq();
return 0;
}
//字符串版的打家劫舍,挺简单的
8.游戏中的学问
#include <iostream>
#include <cstring>
using namespace std;
long long p;
int n,k;
long long circle(){
long long dp[n+1][k+1];
memset(dp,0,sizeof(dp));
dp[3][1]=2;
for(int i=4;i<=n;i++)
for(int j=1;j<=k;j++){
dp[i][j]=(dp[i-1][j]*(i-1))%p;//加入已有的圈
dp[i][j]=(dp[i][j]+dp[i-3][j-1]*(i-2)*(i-1))%p;
//组成新的圈,i已确定,第二个人有i-1个选择,第三个人有i-2个选择
}。
return dp[n][k]%p;
}
int main()
{
// 请在此输入您的代码
scanf("%d%d%lld",&n,&k,&p);
printf("%lld",circle());
return 0;
}
//高中的排列组合题,还是有点难度的
9.蜗牛
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5 + 10;
int a[N],b[N],x[N];//a[i]表示窝牛在第i个轴的高度;
double f[N][2];//f[N][0]表示,到达第n个点的最小时间;f[N][1] 表示到达第n个点的a[n]这个高度的最短时间;
int main() {
int n;
scanf("%d",&n);
for(int i = 1; i <= n;i++)
scanf("%d",&x[i]);
for(int i = 1; i < n;i++)
scanf("%d %d",&a[i],&b[i+1]);
f[1][0] = x[1];
f[1][1] = x[1] + a[1] / 0.7;
for(int i = 2;i <= n;i++) {
f[i][0] = min(f[i-1][0] + (x[i] - x[i-1]),f[i-1][1]+ b[i] / 1.3);
if(a[i] >= b[i])
f[i][1] = min(f[i][0]+a[i]/0.7,f[i-1][1]+(a[i]-b[i])/0.7);
else
f[i][1] = min(f[i][0]+a[i]/0.7,f[i-1][1]+(b[i]-a[i])/1.3);
}
printf("%.2lf",f[n][0]);
return 0;
}//感觉最难的是构造状态转移方程,求解过程比较简单
10.数组分割
#include <iostream>
#include <cstring>
using namespace std;
#define N 1001
#define P 1000000007
int t,n;
long long a[N];
long long SubArr(){
long long dp[n+1][2];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=0;i<n;i++){
if(a[i]%2==0){
dp[i+1][0]=dp[i][0]*2;
dp[i+1][1]=dp[i][1]*2;
}
else{
dp[i+1][0]=(dp[i][0]+dp[i][1]);
dp[i+1][1]=(dp[i][1]+dp[i][0]);
}
dp[i+1][0]%=P;
dp[i+1][1]%=P;
}
return dp[n][0];
}
int main()
{
// 请在此输入您的代码
scanf("%d",&t);
while(t--){
long long sum=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
}
if(sum%2==0)
printf("%lld\n",SubArr());
else
printf("0\n");
}
return 0;
}//主要考察奇偶数相加性质:
奇+偶=奇
偶+偶=偶
奇+奇=偶
感觉构造状态转移方程挺难的
蓝桥杯十四届JavaB组试题C:数组分割详解(dp)-CSDN博客,我是看这篇文章的解析。
11.接龙数组
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int n;
int ChainArr(string s[]){
int x,y,m=0,dp[10];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
x=s[i][0]-'0';
y=s[i][s[i].size()-1]-'0';
dp[y]=max(dp[x]+1,dp[y]);
m=max(m,dp[y]);
}
return n-m;
}
int main()
{
// 请在此输入您的代码
scanf("%d",&n);
string s[n];
for(int i=0;i<n;i++)
cin>>s[i];
if(n==1)
printf("0");
else
printf("%d",ChainArr(s));
return 0;
}//挺简单的题,但是状态转移方程构造很巧妙
这个题解写的很清晰
————部分代码是别人写的题解,本人仅为转载,非原创;