(不易)POJ-2392 sort预处理+多重部分和

来源:互联网 发布:淘宝劲舞团g币怎么刷的 编辑:程序博客网 时间:2024/06/02 05:29

题目大意:一群牛要上太空,给出n种石块,每种石块给出单块高度h_i,使用第i种石头后高度不能超过a_i,数量c_i,要求用这些石块能组成的最大高度


题目链接:点击打开链接


分析:

这个问题为典型的多重部分和,也属于完全背包可行性问题。与裸的多重部分和相比,多了一个条件a_i,所以不能再裸多重部分和的代码了。

根据贪心的思想,对于a_i小的当然是堆在越下面越好,所以不妨先对a_i升序排序,这时当检查到第i种石头时,可以组成的最大高度肯定为a_i,因为a_i为前i种里的最大值。这个时候再裸上一个多重部分和的模板就好了。

状态:dp[i][j]:前i种石头且当前正使用第i种堆出高度j最多剩下多少第i种石头

转移:

若dp[i-1][j]>=0,即前i-1种可以配成j,所以根本用不到第i种,所以剩余C_i种  dp[i][j]=C_i

若j<a[i] || dp[i][j-a[i]]<=0,由于dp[i-1][j]<0,所以要想配成j起码得要有第i种,若j<a[i]则第i种用不到,所以前i种仍配不到j,若dp[i][j-a[i]]<=0,则说明配成j-a[i]时第i种已经无剩余或者甚至无法配成j-a[i],更别说配成j了,        dp[i][j]=-1

其他情况,由于a[i]还有剩,所以dp[i][j]相当于在dp[i][j-a[i]]的基础上多使用了一个a[i],此时   dp[i][j]=dp[i][j-a[i]]-1



附上代码:

#include<iostream>#include<algorithm>using namespace std;struct Block{ int h, a, c; }block[405];int dp[40005];      //dp[i][j]:前i种且当前正使用第i种堆出j时第i种最多剩余的个数 int n, ans = 0;       bool cmp(Block &aa, Block &bb){ return aa.a < bb.a; }int main(){scanf("%d", &n);for (int i = 1; i <= n; i++)scanf("%d%d%d", &block[i].h, &block[i].a, &block[i].c);sort(block + 1, block + n + 1, cmp);memset(dp, -1, sizeof dp);dp[0] = 0;for (int i = 1; i <= n; i++)for (int j = 0; j <= block[i].a; j++)if (dp[j] >= 0) dp[j] = block[i].c;else if (j < block[i].h || dp[j - block[i].h] <= 0) dp[j] = -1;else dp[j] = dp[j - block[i].h] - 1;for (int i = 1; i <= block[n].a; i++)if (dp[i] >= 0) ans = i;printf("%d\n", ans);return 0;}

0 0
原创粉丝点击