题解 P6771 【[USACO05MAR]Space Elevator 太空电梯】

SingularPoint

2020-09-25 21:31:22

Solution

### 题目大意 给出方块种类(<=400),求用现有的的方块在 **使用数目不超过方块个数 ci ,方块所处高度不超过其最大限制高度 ai** 时可以达到的最大高度 ### 分析 “种类”、“个数”、“最大高度”等字眼再加上<=400的数据范围,相信大家很快就能够看出来这是一道DP,将“方块”作为“物品”,“高度”作为“体积”,显而易见——**多重背包**。 1. 定义状态:注意到题目中“高度”一量既是所求答案又是运算的判断条件(即同时作为多重背包的“重量”和“价值”),所以我们可以考虑**将$f(i)$定义为高度 i 是否可行**,得出状态转移方程$f(i)=f(i-h_{i})$,特殊的:$f(0)=1$。 1. 考虑边界:本题中边界有两个:ci和ai。在DP的循环条件中我们可以将ai作为循环终止的条件进行判断,现在考虑对方块使用个数ci的判断: 对于循环中的每种方块 i 达到的高度 j ,我们可以设定一个计数数组来记录这个状态下使用的方块 i 的个数,**到达高度 j 时的使用个数就等于$cnt(i,j-h_{i})+1$**。 1. 特殊情况:在循环的途中我们发现,如果在前面的循环中计算了 ai 较大的方块,后面 ai 较小的方块将不会被计算,所以我们可以在DP前使用一个**贪心策略**:将方块按照 ai 从小到大排序。 有了上面的分析过程,相信代码也很快可以完成辣~ ### 代码 ```cpp #include<cstdio> #include<algorithm> using namespace std; const int M=200000; int n,ans=0; struct node{ int h,c,a; }p[405]; int cnt[405][M]; bool f[M]; bool cmp(node x,node y) {return x.a<y.a;} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&p[i].h,&p[i].a,&p[i].c); sort(p+1,p+n+1,cmp);//将方块按照ai排序以避免出错 f[0]=1; for(int i=1;i<=n;i++) for(int j=p[i].h;j<=p[i].a;j++) if(f[j-p[i].h]&&!f[j]&&cnt[i][j-p[i].h]<p[i].c){//在这里必需要有“!f[j]”的判断,以防cnt被重复计算 cnt[i][j]=cnt[i][j-p[i].h]+1; f[j]=1; ans=max(ans,j);//ans记录答案(可行的最大高度) } printf("%d",ans); return 0; } ``` 完结撒fa~