首页 > ACM题库 > HDU-杭电 > HDU 3466-Proud Merchants-动态规划-[解题报告]HOJ
2014
03-30

HDU 3466-Proud Merchants-动态规划-[解题报告]HOJ

Proud Merchants

问题描述 :

Recently, iSea went to an ancient country. For such a long time, it was the most wealthy and powerful kingdom in the world. As a result, the people in this country are still very proud even if their nation hasn’t been so wealthy any more.
The merchants were the most typical, each of them only sold exactly one item, the price was Pi, but they would refuse to make a trade with you if your money were less than Qi, and iSea evaluated every item a value Vi.
If he had M units of money, what’s the maximum value iSea could get?

输入:

There are several test cases in the input.

Each test case begin with two integers N, M (1 ≤ N ≤ 500, 1 ≤ M ≤ 5000), indicating the items’ number and the initial money.
Then N lines follow, each line contains three numbers Pi, Qi and Vi (1 ≤ Pi ≤ Qi ≤ 100, 1 ≤ Vi ≤ 1000), their meaning is in the description.

The input terminates by end of file marker.

输出:

There are several test cases in the input.

Each test case begin with two integers N, M (1 ≤ N ≤ 500, 1 ≤ M ≤ 5000), indicating the items’ number and the initial money.
Then N lines follow, each line contains three numbers Pi, Qi and Vi (1 ≤ Pi ≤ Qi ≤ 100, 1 ≤ Vi ≤ 1000), their meaning is in the description.

The input terminates by end of file marker.

样例输入:

2 10
10 15 10
5 10 5
3 10
5 10 5
3 5 6
2 7 3

样例输出:

5
11

每件物品有一个限制,只有当你当前现金大于qi的时候才会卖给你。

这题好好想了一下,跟之前做过的一道题有些类似。考虑简化版,有两个物品(p1,q1,v1),(p2,q2,v2),然后物品1先放的话,物品2就可以借助物品1产生的各种状态来进行下一步转移,而如果物品2的q2值过高,在这个[q2,m]的区间内都不存在物品1造成的新状态的话,那么物品1的状态就没有得到利用。而如果交换顺序,先放了物品2,那么显然物品1就可以利用物品2产生的新状态。

所以物品1能从物品2转移的状态区间其实是[min(q1+p2,m),m],物品2能从物品1转移的状态区间是[min(q2+p1,m),m]。所以尽可能地复用这个区间,让区间小的先来,区间大的后来,这样排序之后所有物品都能从前面的物品得到新状态进行转移。

而普通的01背包之所以不需要排序,是因为p1==q1,p2==q2,排序跟不排是一回事。这一类的dp题要注意后效性是否存在,如果存在通过改变顺序之类的办法来取消后效性。再有杭电上饭卡那题,qi恒定为5,所以也是需要排序的。

#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <string>
#include <bitset>
#include <memory>
#include <complex>
#include <numeric>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <ctype.h>
#include <locale.h>

using namespace std;

#pragma pack(4)

const double  eps = 1e-8;
const double   pi = acos(-1.0);
const int     inf = 0x7f7f7f7f;

#define loop(a,n)                            \
    for(int i=0;n>i;i++)                     \
        cout<<a[i]<<(i!=n-1?' ':'\n')
#define loop2(a,n,m)                         \
    for(int i=0;n>i;i++)                     \
        for(int j=0;m>j;j++)                 \
            cout<<a[i][j]<<(j!=m-1?' ':'\n')

#define   at(a,i) ((a)&(1<<(i)))
#define   nt(a,i) ((a)^(1<<(i)))
#define set1(a,i) ((a)|(1<<(i)))
#define set0(a,i) ((a)&(~(1<<(i))))

#define cmp(a,b) (fabs((a)-(b))<eps?0:(((a)-(b))>eps?+1:-1))

#define lmax(a,b) ((a)>(b)?(a):(b))
#define lmin(a,b) ((a)<(b)?(a):(b))
#define fmax(a,b) (cmp(a,b)>0?(a):(b))
#define fmin(a,b) (cmp(a,b)<0?(a):(b))

const int MAXV = 5002;

struct node
{
    int p,q,v;
    bool operator < (node argu) const
    {
        return q-p>argu.q-argu.p;
    }
}a[502];

int n,m,dp[MAXV];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("Proud Merchants.txt","r",stdin);
    #else
    #endif

    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i=0;n>i;i++)
        {
            scanf("%d %d %d",&a[i].p,&a[i].q,&a[i].v);
        }
        sort(a,a+n);
        memset(dp,-1,sizeof(dp)); dp[m]=0;
        int ans=0;
        for(int i=0;n>i;i++)
        {
            for(int j=max(0,a[i].q-a[i].p);m>=j+a[i].p;j++)
            {
                if(dp[j+a[i].p]!=-1)
                {
                    dp[j]=max(dp[j],dp[j+a[i].p]+a[i].v);
                    ans=max(ans,dp[j]);
                }
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}

参考:http://blog.csdn.net/speedcell4/article/details/8699978


  1. 第二个方法挺不错。NewHead代表新的头节点,通过递归找到最后一个节点之后,就把这个节点赋给NewHead,然后一直返回返回,中途这个值是没有变化的,一边返回一边把相应的指针方向颠倒,最后结束时返回新的头节点到主函数。

  2. 很高兴你会喜欢这个网站。目前还没有一个开发团队,网站是我一个人在维护,都是用的开源系统,也没有太多需要开发的部分,主要是内容整理。非常感谢你的关注。

  3. 站长好。我是一个准备创业的互联网小白,我们打算做一个有关国*际*游*学的平台。手上也有了一些境外资源。现阶段的团队现在没有cto.原意出让一些管理股寻找一个靠谱的技术专家做合伙人, 不知道是不是能得到您的帮助。发个帖子或者其他方式。期待您的回应。可以加我微信tianxielemon聊聊。