【DP水题】P4823 [TJOI2013]拯救小矮人

题目传送门

题目

题目描述
一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。
对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。
如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。
输入格式
第一行一个整数N, 表示矮人的个数,接下来N行每一行两个整数Ai和Bi,最后一行是H。(Ai,Bi,H<=10^5)
输出格式
一个整数表示对多可以逃跑多少小矮人
输入输出样例
输入 #1 复制
2
20 10
5 5
30
输出 #1 复制
2
输入 #2 复制
2
20 10
5 5
35
输出 #2 复制
1
说明/提示
30%的数据 N<=200
100%的数据 N<=2000

题意

大概就是有n个人,他们身高为a[i].a,臂长为a[i].b
然后搭人体上h的高度的墙,最上面的人可以使用手臂爬上去
求最多多少人能爬出

解答

由条件我们可以知道,越多人爬出去解法越优
故搭人梯的人应该尽量少,越高的人搭人体越有优
所以我们进行排序

之后dp[i][j]表示 i个人,走了j的高度

如果之前的人梯+第i个人的高度+第i个人的臂长>=墙的高度
那么第i个人的行动有2种方案,走或者留下
留下:dp[i][j]=dp[i-1][j]
走:dp[i][j+1]=dp[i-1][j]

最优答案就是 f[n][i]

代码

由于h<=10000且n<=2000,所以怕数组过大,就进行状态压缩
用数组滚动代替高度的维度
其余不变

#include<bits/stdc++.h>
using namespace std;
int n,h;
int dp[2010];
struct node{
	int a;
	int b;
};
node a[2010];
bool cmp(node x,node y){
	return x.a+x.b<y.a+y.b;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].a>>a[i].b;
	}
	cin>>h;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		dp[i]=-0x7f7f7f7f;
		dp[0]+=a[i].a;
	}
	for(int i=1;i<=n;i++){
		for(int j=i;j>=1;j--){
			if(dp[j-1]+a[i].b>=h){
				dp[j]=max(dp[j],dp[j-1]-a[i].a);
			}
		}
	}
	for(int i=n;i>=0;i--){
		if(dp[i]>=0){
			cout<<i;
			return 0;
		}
	}
}

拓展

樱狸子机房学姐的点拨下,我突然想起这道题目还可以用背包的思维
小矮人是选或者不选
墙的高度就是背包容量
小矮人高度就是物品体积
所以这道题用背包也很容易想通

END

猜你喜欢

转载自www.cnblogs.com/pqh-/p/13378108.html