动态规划-背包问题
- 1.P1060 开心的金明
https://www.luogu.org/problemnew/solution/P1164
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100 #define MAX 1<<30 #define V vector<int> using namespace std; int v[LEN],p[LEN];//价钱,重要度 int dp[LEN][30001]; int n,m; int main(){ // freopen("D:/CbWorkspace/动态规划/开心的王明.txt","r",stdin); int i,j; scanf("%d %d",&n,&m); F(i,1,m+1){ scanf("%d",&v[i]); scanf("%d",&p[i]); } F(i,1,m+1){ F(j,1,n+1){ if(v[i]>j) dp[i][j]=dp[i-1][j]; else{ dp[i][j]=max(dp[i-1][j], dp[i-1][j-v[i]] + p[i] * v[i]); } } } printf("%d",dp[m][n]); return 0; }
- 2.P1164 小A点菜
https://www.luogu.org/problemnew/show/P1164
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 100 #define MAX 1<<30 #define V vector<int> using namespace std; int v[LEN];//价钱 int dp[101][1001]; int n,m; int main(){ freopen("小A点菜.txt","r",stdin); int i,j; scanf("%d %d",&n,&m);//n种,m元 F(i,1,n+1) scanf("%d",&v[i]); F(i,1,n+1){ bool isSet=false; F(j,1,m+1){ if(isSet){ dp[i][j]=dp[i][j-1];continue;} if(v[i]>j) dp[i][j]=dp[i-1][j]; else{ dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+1); } } } printf("%d",dp[n][m]); return 0; }
定义f[i][j]为用前i道菜用光j元钱的办法总数,其状态转移方程如下:
(1)if(j==第i道菜的价格)f[i][j]=f[i-1][j]+1; (2)if(j>第i道菜的价格) f[i][j]=f[i-1][j]+f[i-1][j-第i道菜的价格]; (3)if(j<第i道菜的价格) f[i][j]=f[i-1][j];
说的简单一些,这三个方程,每一个都是在吃与不吃之间抉择。若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前i-1道菜的办法总数。依次递推,在最后,我们只要输出f[n][m]的值即可。