目录 |
印章
用到了动态规划
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 在这道题中我们首先明确dp[i][j]代表的是i次凑齐j种的概率
- dp[i][j]=dp[i-1][j-1]*((n-j+1)*1.0/n)+dp[i-1][j]
//对应的是第i次的与前i-1次取得都不重复*这个概率+第i次的与前i-1次的重复*这个概率
- 如果说i<j则dp[i][j]=0;
- 如果说j=1时dp[i][1]=(1.0/n)^(i-1)(代表在i次全部取的是一种从n种里取1种的i次方在乘n之所以乘n是因为有n种嘛)
#include <iostream>
#include <algorithm>
#include<cmath>
#include<iomanip>//保留小数
using namespace std;
float dp[21][21];
//学习动态规划
int main(){
int n,m;//n种m张
cin>>n>>m;
int i,j;
float p=1.0/n;//每种出现的概率;
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
if(i<j){
dp[i][j]=0;
}
else if(j==1){
dp[i][1]=pow(p,i-1);//一种的话i次取得是相同的
}
else{
dp[i][j]=dp[i-1][j-1]*((n-j+1)*1.0/n)+dp[i-1][j]*(j*1.0/n);//不重复的和重复的
}
}
}
cout<<fixed<<setprecision(4)<<dp[m][n]<<endl;
}
拿金币
以后改变下数组的定义大小时候的写法
const int N = 10010;(先定义一个常量)
int dp[N][N];
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int dp[N][N],res;
int main(){
int n;
cin>>n;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j ++){
cin>>dp[i][j];
}
}
dp[0][1] = dp[1][0] = 0;
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
dp[i][j] = max(dp[i-1][j],dp[i][j-1])+dp[i][j];
}
}
for(int i = 1;i <= n;i ++){
res = max(dp[n][i],res);
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<dp[i][j]<<" ";
// }
// cout<<endl;
// }
cout<<res;
return 0;
}
完全背包问题
这个难点在于每种价值的物品是无限的;
dp[i][v]前i种物品总重不超过v时的最大值;
c[i]是第i种物品的所占用的容量;w[i]是第i种物品的价值;
dp[i][v]=max(dp[i-1][v],dp[i-1][v-c[i]]+w[i],dp[i-1][v-2*c[i]]+2*w[i]....)//不知道加几个物品他为最大
//多理解多做这种题就会了
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1000;
int dp[N][N];
int main(){
int N,M;//N种M容量
cin>>N>>M;
int c[N],w[N];//每种的大小和价值
for(int i=1;i<=N;i++){
cin>>c[i];//价值
cin>>w[i];//容量
}
//我们不用二维数组我们用一维数组来实现
for(int i=1;i<=N;i++){
for(int j=0;j<=M;j++){//二维数组每一项都应该有值的
if(j>=c[i]){
dp[i][j]=max(dp[i-1][j],dp[i][j-c[i]]+w[i]);
}
else{
dp[i][j]=dp[i-1][j];
}
}
}
for(int i=1;i<=N;i++){
for(int j=0;j<=M;j++){
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
}