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

题目传送门:

https://www.luogu.com.cn/problem/P6771

题目大意

给出方块种类(<=400),求用现有的的方块在 使用数目不超过方块个数 ci ,方块所处高度不超过其最大限制高度 ai 时可以达到的最大高度

分析

“种类”、“个数”、“最大高度”等字眼再加上<=400的数据范围,相信大家很快就能够看出来这是一道DP,将“方块”作为“物品”,“高度”作为“体积”,显而易见——多重背包

  1. 定义状态:注意到题目中“高度”一量既是所求答案又是运算的判断条件(即同时作为多重背包的“重量”和“价值”),所以我们可以考虑将f(i)定义为高度 i 是否可行,得出状态转移方程 f(i)=f(i−hi),特殊的: f(0)=1。

  2. 考虑边界:本题中边界有两个:ci和ai。在DP的循环条件中我们可以将ai作为循环终止的条件进行判断,现在考虑对方块使用个数ci的判断: 对于循环中的每种方块 i 达到的高度 j ,我们可以设定一个计数数组来记录这个状态下使用的方块 i 的个数,到达高度 j 时的使用个数就等于 cnt(i,j−hi)+1

  3. 特殊情况:在循环的途中我们发现,如果在前面的循环中计算了 ai 较大的方块,后面 ai 较小的方块将不会被计算,所以我们可以在DP前使用一个贪心策略:将方块按照 ai 从小到大排序。

有了上面的分析过程,相信代码也很快可以完成辣~

代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int M=200000;
 5 int n,ans=0;
 6 struct node{
 7     int h,c,a;
 8 }p[405];
 9 int cnt[405][M];
10 bool f[M];
11 bool cmp(node x,node y)
12 {return x.a<y.a;}
13 int main()
14 {
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++)
17         scanf("%d%d%d",&p[i].h,&p[i].a,&p[i].c);
18     sort(p+1,p+n+1,cmp);//将方块按照ai排序以避免出错 
19     f[0]=1;
20     for(int i=1;i<=n;i++)
21         for(int j=p[i].h;j<=p[i].a;j++)
22             if(f[j-p[i].h]&&!f[j]&&cnt[i][j-p[i].h]<p[i].c){//在这里必需要有“!f[j]”的判断,以防cnt被重复计算 
23                 cnt[i][j]=cnt[i][j-p[i].h]+1;
24                 f[j]=1;
25                 ans=max(ans,j);//ans记录答案(可行的最大高度) 
26             }
27     printf("%d",ans);
28     return 0;
29  } 

完结撒fa~

posted @ 2020-09-25 21:38  SingularPoint  阅读(234)  评论(0编辑  收藏  举报