【题解】洛谷 P6771 [USACO05MAR]Space Elevator 太空电梯
题目传送门:
https://www.luogu.com.cn/problem/P6771
题目大意
给出方块种类(<=400),求用现有的的方块在 使用数目不超过方块个数 ci ,方块所处高度不超过其最大限制高度 ai 时可以达到的最大高度
分析
“种类”、“个数”、“最大高度”等字眼再加上<=400的数据范围,相信大家很快就能够看出来这是一道DP,将“方块”作为“物品”,“高度”作为“体积”,显而易见——多重背包。
-
定义状态:注意到题目中“高度”一量既是所求答案又是运算的判断条件(即同时作为多重背包的“重量”和“价值”),所以我们可以考虑将f(i)定义为高度 i 是否可行,得出状态转移方程 f(i)=f(i−hi),特殊的: f(0)=1。
-
考虑边界:本题中边界有两个:ci和ai。在DP的循环条件中我们可以将ai作为循环终止的条件进行判断,现在考虑对方块使用个数ci的判断: 对于循环中的每种方块 i 达到的高度 j ,我们可以设定一个计数数组来记录这个状态下使用的方块 i 的个数,到达高度 j 时的使用个数就等于 cnt(i,j−hi)+1。
-
特殊情况:在循环的途中我们发现,如果在前面的循环中计算了 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~