DP问题就是递归的一种,递归对于本人很不好理解 。
1.最少硬币问题
5种面值1,5,10,25,50.给出需要的金额总值,算最少硬币数达到该金额。
书上的解释比较好理解
#include<bits/stdc++.h>
using namespace std;
const int money = 251;
const int value = 5;
int type[value]={1,5,10,25,50};
int min1[money]; //每个金额对应在最少在硬币数量
void solve(){
for(int i=0;i<money;i++)
min1[i]=INT_MAX;//int范围在最大值
min1[0]=0; //0元0个硬币 递归出口
for(int i=0;i<value;i++){
for(int j=type[i];j<money;j++){
min1[i] = min(min1[j] , min1[ j - type[i] ] + 1);// +1 放入硬币在个数为1
}
}
}
int main(){
int s;
solve();
while(cin >>s){
cout<<min1[s]<<endl;
}
return 0;
}
2.Coin Change hud 2069
题目描述:
有5中面值硬币1,5,10,25,50;输入金钱s,输出组合方案的数量,s<=250,数量<=100。
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int coin = 101; //要求不能超过100
const int mo = 251; //金额不能超过250
int dp[mo][coin] = {0};
int type[5] = {1,5,10,25,50};//5种面值
void solve(){
dp[0][0] = 1;
for(int i=0;i<5;i++){ //5种面值
for(int j=1;j<coin;j++){ //不超过100个
for(int k=type[i];k<mo;k++){
dp[k][j]+=dp[k-type[i]][j-1];
}
}
}
}
int main(){
int s;
int ans[mo] = {0};
solve();
for(int i=0;i<mo;i++){ //对每个金额计算有多少种组合方案,打表
for(int j=0;j<coin;j++){ //从0开始注意dp[0][0]=1
ans[i]+=dp[i][j];
}
}
while(cin>>s)
cout<<ans[s]<<endl;
return 0;
}
3.0/1背包问题
题目描述:
有多个物品,重量不同,价值不同,以及一个容量有限的背包,一样物品要么选,要么不选,使背包的容量达最大值。
/*********
3 10
5 6
2 3
2 2
11
*********/
#include<bits/stdc++.h>
using namespace std;
const int N=1000+5;
int w[N],v[N]; //数组w[i]指第i件物品的重量,v[i]价值
int dp[N][N]; //动态记录价值
int dp1[N];
int n,c; //n指有n件物品,c指背包最大承重
int main(){
//用dp方程建表,行表示物品[1,n],列表示背包容量[1,c]
//dp[i][j]表示容量为j的背包选择前i件物品的最大价值和
memset(dp,0,sizeof(dp));//dp初始化为0
memset(dp1,0,sizeof(dp1));
cin >> n >> c;
for(int i = 1;i <= n;i++)
cin >>w[i] >> v[i];//输入物品重量和质量
for(int i = 1;i <= n;i++){
//一.j结束于w[i],不用判断 j-w[i]的正负情况
// for(int j = w[i];j <=c;j++){
// dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]] + v[i]);
// }
//二.比较容易理解
// for(int j = 1;j<=c;j++){
// if(j < w[i]) //第i件太重,装不下
// dp[i][j] = dp[i-1][j];
// else //不选当前物品和选当前物品(背包容量变为j-w[i])两种方案求最大值
// dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]] + v[i]);
// }
//三. 用一维数组实现
for(int j = c;j >= w[i];j--){//从右往左,每次用到的是上一轮数据的左边,不会被覆盖
dp1[j] = max(dp1[j],dp1[j-w[i]]+v[i]);
}
}
//printf("%d\n",dp[n][c]);
printf("%d\n",dp1[c]);
return 0;
}
4.完全背包问题
题目描述
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
输入
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输出
仅一行,一个数,表示最大总价值。
样例输入
10 4 2 1 3 3 4 5 7 9
样例输出
max=12
#include<bits/stdc++.h>
using namespace std;
const int N=1000+5;
int w[35],v[35]; //数组w[i]指第i件物品的重量,v[i]价值
int dp[N][N]; //动态记录价值
int n,c; //n指有n件物品,c指背包最大承重
int main(){
memset(dp,0,sizeof(dp));
cin >> c >>n;
for(int i=1;i<=n;i++)
cin >> w[i] >> v[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=c;j++){
if(j<w[i])
dp[i][j] = dp[i-1][j];
else
//这里是重点dp[i][j-w[i]]+v[i]
}
}
printf("max=%d\n",dp[n][c]);
return 0;
}