最长上升子序列(LIS):
题目
给定长度为的序列,从中选取一个子序列,这个子序列需要单调递增。问最长上升子序列(LIS)的长度。
eg:(1,5,2,3,11,7,9) LIS=(1,2,3,7,9) 长度为5
做法(动态规划):
记f(x)为以a[x]结尾的LIS长度,那么LIS=max{f(x)}
f(x)如何求:
- 考虑比x小的每一个p ,如果a[x]>a[p},那么f(x)=f§+1
状态转移方程:
- f(x)=max{f§}+1
代码实现
#include<bits/stdc++.h>
using namespace std;
int a[100];
int dp[100];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++){
if(a[j]<a[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
printf("dp[%d]=%d ",i,dp[i]);
}
return 0;
}
硬币问题
题目:
有1,3,5分面额的硬币,给定一个面值11,问组成给定面值所需最少硬币的数量是多少?
做法(动态规划):
- F(n)只与F(n-1),F(n-5),f(n-11)有关
- F(n)=min{F(n-1)+1,F(n-5)+1,f(n-11)+1}
代码实现
#include<bits/stdc++.h>
#define for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int dp[100];
int cost;
int main(){
dp[0]=0;
for(i,1,15){
cost=15;
if(i-1>=0) cost=min(cost,dp[i-1]+1);
if(i-5>=0) cost=min(cost,dp[i-5]+1);
if(i-11>=0) cost=min(cost,dp[i-11]+1);
dp[i]=cost;
printf("dp[%d]=%d ",i,dp[i]);
}
return 0;
}
01背包问题
题目:
有n个物体(由输入数据组数决定),每个物体都有各自的体积和价值。现给定一容量一定的背包,求怎样装才能让背包所装总物体价值最大?记背包容量为8,物体体积,价值如下:
物品编号 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
物品重量 | 2 | 3 | 4 | 5 |
物品价值 | 3 | 4 | 5 | 8 |
做法(动态规划):
记f(k,w):当前背包容量为w,现在有k件物品可以偷
每次偷商品有两种可能:
- 包的容量比物体小,不能装入背包了,此时的价值与前一个相同
- 包的容量可以装下当前的物体,此时的价值等于背包容量的价值+当前物品的价值
代码实现:
#include<bits/stdc++.h>
#define for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int f[5][9]={0}; //记录所偷盗的价值,前面是物品,后面是价值
int w[5]={0,2,3,4,5};//物品的重量
int v[5]={0,3,4,5,8};//物品的价值
int main(){
memset(f,0,sizeof(f));
for(i,1,4){ //遍历物品的容量
for(j,1,8){//j代表背包容量
if(w[i]>j) //物品的重量大于背包容量了,不可以偷
f[i][j]=f[i-1][j];//此时的价值不变
else //下面是不偷 , 下面是偷
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
}
}
for(i,0,4)
for(j,0,8)
printf("f[%d][%d]=%d\n",i,j,f[i][j]);
return 0;
}