POJ2392 Space Elevator 详解 附加限制的多重背包( 多重部分和)

Space Elevator

  • Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others)

Description

The cows are going to space! They plan to achieve orbit by building a sort of space elevator: a giant tower of blocks. They have K (1 ≤ K ≤ 400) different types of blocks with which to build the tower. Each block of type i has height hi (1 ≤ hi ≤ 100) and is available in quantity ci (1 ≤ ci ≤ 10). Due to possible damage caused by cosmic rays, no part of a block of type i can exceed a maximum altitude ai (1 ≤ ai ≤ 40000).

Help the cows build the tallest space elevator possible by stacking blocks on top of each other according to the rules.

Input

* Line 1: A single integer, K

* Lines 2..K+1: Each line contains three space-separated integers: hiai, and ci. Line i+1 describes block type i.

Output

* Line 1: A single integer H, the maximum height of a tower that can be built

Sample Input

3
7 40 3
5 23 8
2 52 6

Sample Output

48

Hint

OUTPUT DETAILS:

From the bottom: 3 blocks of type 2, below 3 of type 1, below 6 of type 3. Stacking 4 blocks of type 2 and 3 of type 1 is not legal, since the top of the last type 1 block would exceed height 40.

题目意思:

有K组数,后面三个数h,a,c分别表示一块砖的高度 h 、用这种砖的最大限制高度 a 和用这种砖的最多块数 c

求用这些砖叠在一起的最大高度;

两种解题方法:

转化为由多重背包--->01背包;(注:与其他普通的01背包不同的是每种i砖的使用有一个高度限制a)

② 使用多重部分和的思想 限制条件为最大高度;


①  多重背包--->01背包 AC代码:


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define MAXN 40005

int dp[MAXN];//d[i]表示石块能组成的高度为i
///容量即价值
struct Node
{
    int h,a,c;//分别表示一块砖的高度、用这种砖的最大高度和最多块数
} s[MAXN];

int cmp(Node x,Node y)//结构体排序
{
    return x.a<y.a;//升序
}

int main()
{
    int n,i,j,k,ans=0;
    cin>>n;
    for(i=0; i<n; ++i)
        cin>>s[i].h>>s[i].a>>s[i].c;///因为每块砖的高度限制条件不一样
        
            ///所以不能将所有砖的数量直接在这用二进制进行分解
            
    sort(s,s+n,cmp);//按最大高度升序排列
    
    memset(dp,0,sizeof(dp));//初始化
    
    for(i=0; i<n; ++i)//n种砖块,使用多重背包
    {
        if(s[i].h*s[i].c>=s[i].a)//完全背包
        
            for(j=s[i].h; j<=s[i].a; j++)
                
                dp[j]=max(dp[j],dp[j-s[i].h]+s[i].h);
        
        else//01背包
        {
            for(k=1; k<=s[i].c; k<<=1) //二进制优化分解数量
            {
                for(j=s[i].a; j>=k*s[i].h; --j)///砖块使用的限制高度
                
                    dp[j]=max(dp[j],dp[j-k*s[i].h]+k*s[i].h);///容量即价值
                    
                s[i].c-=k;//减去用过的数量
            }
            if(s[i].c>0) ///还剩余未分解完的
                
            for(j=s[i].a; j>=s[i].h*s[i].c; --j)
                
                dp[j]=max(dp[j],dp[j-s[i].h*s[i].c]+s[i].h*s[i].c);
        }
    }
    for(i=1; i<=s[n-1].a; ++i)///s[n-1].a表示所有限制高度中价值的最大值
        
        ans=max(ans,dp[i]);///找出石块能组成的最大高度
    
    cout<<ans<<endl;
    return 0;
}



多重部分和AC代码:


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 40005

int dp[MAXN];//d[i]表示能组成的i高度时 还剩有几块石块

struct Node
{
  int h,a,c;//分别表示一块砖的高度、用这种砖的最大高度和最多块数
} s[MAXN];
int cmp(Node x,Node y)//结构体排序
{
  return x.a<y.a;//升序
}
int main()
{
  int n,i,j,ans=0;
  cin>>n;
  for(i=0; i<n; ++i)
    cin>>s[i].h>>s[i].a>>s[i].c;
    
  sort(s,s+n,cmp);//按最大高度 升序排列 从低到高
  
  memset(dp,-1,sizeof dp);
  
  ///以下 以从低开始建楼的思路 来想 即必须有已建好的高度 才可以在前面的高度上 加高
  
  dp[0]=0;///从0开始建塔 地基
  for(i=0; i<n; i++)///每种砖头  多重部分和
    for(j=0; j<=s[i].a; j++)///第i种砖头所能组成塔的最大高度
    {
      if (dp[j]>=0) dp[j]=s[i].c; ///塔高j已组成,所以在建好塔高j时 第i种砖还剩有s[i].c个块可用
      
      else if (j<s[i].h || dp[j-s[i].h] <=0) dp[j]=-1; ///塔高<块高 || 塔高 j-s[i].h 在之前还没组成(砖块高无法组成的塔高)
      
      else if (j>=s[i].h && dp[j-s[i].h]>0) ///塔高>=块高 && j-s[i].h 高的塔已存在
      
        dp[j] = dp[j-s[i].h]-1;///用 s[i].h 组成塔高j后,用了一个 i型的砖 剩余砖块减1
    }
  for (i=s[n-1].a; i>=0; --i)
    if(dp[i]>=0)
    {
      ans=i;
      break;
    }
  cout<<ans<<endl;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41668093/article/details/80489730