Space Elevator(多重背包求最大可行方案)

Space Elevator

题目

给n种砖,每种砖有最大高度限制mx,和数量限制x,求最大累计高度。

思路

  • 这是一个完全背包求最大方案问题,可以说是求方案可行性的问题的一个子集。
    所以可以类比其定义dp
  • 定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为考虑前i种物品,累加j时,第i种物品的剩余个数。
  • 状态转移,首先如果前 i − 1 i-1 i1种已经可以拼出 j j j,也即 d p [ i − 1 ] [ j ] ! = − 1 dp[i-1][j]!=-1 dp[i1][j]!=1
    之后,如果还没有凑出j的方案,那么我们就要考虑添加第i种砖块。
    显然它可以从 d p [ i ] [ j − h i ] dp[i][j-h_i] dp[i][jhi]转移过来.
    可以写出状态转移方程
    d p [ i ] [ j ] = { a [ i ] , d p [ i − 1 ] [ j ] ! = − 1 d p [ i ] [ i − h i ] − 1 , d p [ i ] [ i − h i ] > 0 , 不 超 限 dp[i][j] = \begin{cases} a[i] &,dp[i-1][j]!=-1\\ dp[i][i-h_i] -1 & ,dp[i][i-h_i]>0 ,不超限\\ \end{cases} dp[i][j]={a[i]dp[i][ihi]1,dp[i1][j]!=1,dp[i][ihi]>0,
  • 最后考虑每种的限制,从低到高排应该为最不浪费的情况.
    PS:空间要优化到一维.
    PS2:该算法缺点是二维不能过大,本题40000,完全可以接受

AC代码

时间复杂度: O ( n m ) O(nm) O(nm)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<fstream>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 10 + 400, mod = 1e9 + 7;
int n;
struct node
{
	int h, mx, n;
} a[N];
int dp[N * 100];// 定义dp[i][j]为考虑前i个砖,叠到j米的方案集合,记录第i种砖剩余个数。
//  规定 dp[i][j]=-1为无法实现的方案。
bool cmp(node a, node b)
{
	return a.mx < b.mx;
}
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i].h >> a[i].mx >> a[i].n;
	sort(a + 1, a + 1 + n, cmp);
	int m = a[n].mx;
	memset(dp, -1, sizeof dp);
	dp[0] = 0;// 初始化,规定前0个砖搭0米,剩余0
	for (int i = 1; i <= n; i++)
		for (int j = 0; j <= m; j++)
		{
			if (dp[j] != -1)// 如果已经可以搭j米,不花费第i种砖
				dp[j] = a[i].n;
			else if (j - a[i].h >= 0 && dp[j - a[i].h] > 0 && j<=a[i].mx)
				dp[j] = dp[j - a[i].h] - 1;// 如果不越界,且有第i种砖剩余 
										  // 且未超过限制 ,用一块砖搭一块。
		}
	for(int j=m;j>=0;j--)// 找最大可行方案
		if(dp[j]!=-1)
		{
			cout<<j<<endl;
			return;
		}
}
signed main()
{
	ios::sync_with_stdio();
	cin.tie();
	cout.tie();

	solve();

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值