01背包 + 排序
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3466
题目大意:n中商品,m元钱,每种商品都有p,q,v属性,p价格,q表示买这种商品你需要带q元老板才愿意和你交易,v这种商品的实际价值,求问最多可以获得多少价值。
这题是有先决条件的dp,会导致没达到限制条件的 j 在 i+1 后达到,但没法正确更新,没法直接解决这个问题,就要用到排序解决。
比如对于第二个样例,第一件商品 5 10 5只会把dp[10]更新出来,但实际上花费了5,更新第二个商品时,需要dp[10]=max(dp[10-5]+6,dp[10]),此时需要借助上一层的dp[5],但实际上此时dp[5]还没有更新。
发现先不管价值v,如果有 5 10 和 10 12 的两件商品,那么要想全部买下,顺序会影响需要的钱。 分别需要的钱为 Q2+P1 = 17 和 Q1+P2 = 20,肯定选需要钱少的那个Qx+Py ,即先买y , 当Q2+P1 > Q1+P2 , 可以化为 Q2-P2 > Q1-P1 , 即 Qx - Px 大的先考虑买不买。
并且,这个抉择要用记忆化搜索 dfs 才能直接模拟,如果用循环迭代,则要倒过来循环,也可以直接排序,按照 Qx + Py 从小打大的顺序。
记忆化搜索写法:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int dp[555][5555]; 7 int N,M; 8 typedef struct{ 9 int q,p,v; 10 }node; 11 node a[555]; 12 bool cmp(node a,node b){ 13 return a.q-a.p>b.q-b.p; 14 } 15 int DP(int i,int j){ 16 if(dp[i][j]>=0) return dp[i][j]; 17 int res; 18 if(i==N) return 0; 19 20 else if(j<a[i].q){ 21 res=DP(i+1,j); 22 } 23 else{ 24 res=max(DP(i+1,j),DP(i+1,j-a[i].p)+a[i].v); 25 } 26 return dp[i][j]=res; 27 } 28 29 int main(){ 30 while(scanf("%d%d",&N,&M)!=EOF){ 31 memset(dp,-1,sizeof(dp)); 32 // memset(dp,0,sizeof(dp)); 33 for(int i=0;i<N;i++){ 34 scanf("%d%d%d",&a[i].p,&a[i].q,&a[i].v); 35 } 36 sort(a,a+N,cmp); 37 // for(int i=0;i<N;i++){ 38 // for(int j=0;j<=M;j++){ 39 // if(j<a[i].q) 40 // dp[i+1][j]=dp[i][j]; 41 // else 42 // dp[i+1][j]=max(dp[i][j-a[i].p]+a[i].v,dp[i][j]); 43 // } 44 // } 45 printf("%d ",DP(0,M)); 46 } 47 }
迭代写法:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[555][5555]; int N,M; typedef struct{ int q,p,v; }node; node a[555]; bool cmp(node a,node b){ return a.q-a.p<b.q-b.p; } //int DP(int i,int j){ // if(dp[i][j]>=0) return dp[i][j]; // int res; // if(i==N) return 0; // // else if(j<a[i].q){ // res=DP(i+1,j); // } // else{ // res=max(DP(i+1,j),DP(i+1,j-a[i].p)+a[i].v); // } // return dp[i][j]=res; //} int main(){ while(scanf("%d%d",&N,&M)!=EOF){ // memset(dp,-1,sizeof(dp)); memset(dp,0,sizeof(dp)); for(int i=0;i<N;i++){ scanf("%d%d%d",&a[i].p,&a[i].q,&a[i].v); } sort(a,a+N,cmp); for(int i=0;i<N;i++){ for(int j=0;j<=M;j++){ if(j<a[i].q) dp[i+1][j]=dp[i][j]; else dp[i+1][j]=max(dp[i][j-a[i].p]+a[i].v,dp[i][j]); } } printf("%d ",dp[N][M]); } }