01背包 + 排序 (记忆化搜索) 骄傲的商人(HDU - 3466)

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\n",DP(0,M));
46     }
47 }
View Code

迭代写法:

#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\n",dp[N][M]);
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/-Zzz-/p/11409490.html