Space Elevator
题目
给n种砖,每种砖有最大高度限制mx,和数量限制x,求最大累计高度。
思路
- 这是一个完全背包求最大方案问题,可以说是求方案可行性的问题的一个子集。
所以可以类比其定义dp - 定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为考虑前i种物品,累加j时,第i种物品的剩余个数。
- 状态转移,首先如果前
i
−
1
i-1
i−1种已经可以拼出
j
j
j,也即
d
p
[
i
−
1
]
[
j
]
!
=
−
1
dp[i-1][j]!=-1
dp[i−1][j]!=−1。
之后,如果还没有凑出j的方案,那么我们就要考虑添加第i种砖块。
显然它可以从 d p [ i ] [ j − h i ] dp[i][j-h_i] dp[i][j−hi]转移过来.
可以写出状态转移方程
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][i−hi]−1,dp[i−1][j]!=−1,dp[i][i−hi]>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;
}