HDU 5543 Pick The Sticks:01背包变种

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5543

题意:

  给你N个金条和一张长度为L的桌子。每个金条长度为a[i],价值为w[i]。金条只能在桌子上横着摆一排,并且只要金条的重心(中心)在桌子上,就可以放。问你在桌子上能够摆的金条的最大总价值。

 

题解:

  首先表示状态:

    考虑到第i个金条,在这之前已经占用了j的长度,在k个端点摆了金条。即:dp[i][j][k]

  如何转移(逆推):

    对于第i个金条,有三种决策:摆在桌子中央、摆在桌子端点处、不摆。

    (1)摆在中央:dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-a[i]][k])

    (2)摆在端点:dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-a[i]/2][k-1])

    (3)不摆:  dp[i][j][k] = max(dp[i][j][k], dp[i-1][j][k])

  求dp:枚举i,j,k即可。

  注:(1)由于空间限制,dp[i][j][k]去掉第一维[i],枚举j时从大到小枚举。

    (2)由于计算金条长度的一半时会出现浮点数,所以在读入时就将所有a[i]*=2,并且L*=2。

 

AC Code:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX_N 1005
#define MAX_L 4005
#define MAX_K 5

using namespace std;

int n,l,t;
long long ans;
long long a[MAX_N];
long long w[MAX_N];
long long dp[MAX_L][MAX_K];

void read()
{
    ans=0;
    cin>>n>>l;
    l*=2;
    for(int i=0;i<n;i++)
    {
        cin>>a[i]>>w[i];
        a[i]*=2;
        ans=max(ans,w[i]);
    }
}

void solve()
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        for(int j=l;j>=a[i]/2;j--)
        {
            for(int k=0;k<3;k++)
            {
                if(j-a[i]>=0) dp[j][k]=max(dp[j][k],dp[j-a[i]][k]+w[i]);
                if(k-1>=0) dp[j][k]=max(dp[j][k],dp[j-a[i]/2][k-1]+w[i]);
                ans=max(ans,dp[j][k]);
            }
        }
    }
}

void print()
{
    cout<<ans<<endl;
}

int main()
{
    cin>>t;
    for(int cas=1;cas<=t;cas++)
    {
        cout<<"Case #"<<cas<<": ";
        read();
        solve();
        print();
    }
}

 

posted @ 2017-08-15 02:20  Leohh  阅读(259)  评论(0编辑  收藏  举报