1. 程式人生 > >BZOJ_3174_[Tjoi2013]拯救小矮人_貪心+DP

BZOJ_3174_[Tjoi2013]拯救小矮人_貪心+DP

script 希望 深度 sca rip pan main mem 是我

BZOJ_3174_[Tjoi2013]拯救小矮人_貪心+DP

Description

一群小矮人掉進了一個很深的陷阱裏,由於太矮爬不上來,於是他們決定搭一個人梯。即:一個小矮人站在另一小矮人的 肩膀上,知道最頂端的小矮人伸直胳膊可以碰到陷阱口。對於每一個小矮人,我們知道他從腳到肩膀的高度Ai,並且他的胳膊長度為Bi。陷阱深度為H。如果我 們利用矮人1,矮人2,矮人3,。。。矮人k搭一個梯子,滿足A1+A2+A3+....+Ak+Bk>=H,那麽矮人k就可以離開陷阱逃跑了,一 旦一個矮人逃跑了,他就不能再搭人梯了。
我們希望盡可能多的小矮人逃跑, 問最多可以使多少個小矮人逃跑。

Input

第一行一個整數N, 表示矮人的個數,接下來N行每一行兩個整數Ai和Bi,最後一行是H。(Ai,Bi,H<=10^5)

Output

一個整數表示對多可以逃跑多少小矮人

Sample Input

樣例1

2
20 10
5 5
30

樣例2
2
20 10
5 5
35

Sample Output

樣例1
2

樣例2
1

HINT

數據範圍

30%的數據 N<=200

100%的數據 N<=2000


分析:

這道題其實是在求一個子序列。在某種方案下都能夠逃跑的子序列中最長的一個。

我們先貪心地確定逃跑方案。

首先,對於兩個一定要逃跑的人x和y,如果a[x]+a[y]<b[x]+b[y],說明x比y弱,不妨讓x先逃跑。

於是我們可以按a+b排一下序。

然後找最長的子序列。設f[i][j]為前i個人,走了j個後最高的高度。

f[i][j]=f[i-1][j]; f[i][j]=max(f[i][j],f[i-1][j-1]-a[j])(b[j]+f[i-1][j-1]>=h)

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 2050
struct A {
	int a,b;
}a[N];
int h,n,f[N][N];
bool cmp(const A &x,const A &y) {
	return x.a+x.b<y.a+y.b;
}
int main() {
	scanf("%d",&n);
	int i, ans=0, j;
	memset(f,-1,sizeof(f));
	f[0][0]=0;
	for(i=1;i<=n;++i) scanf("%d%d",&a[i].a,&a[i].b),f[0][0]+=a[i].a;
	sort(a+1,a+n+1,cmp);
	scanf("%d",&h);
	for(i=0;i<n;++i) {
		f[i+1][0]=f[i][0];
		for(j=0;j<=ans;j++) {
			f[i+1][j+1]=f[i][j+1];
			if(f[i][j]+a[i+1].b>=h) {
				f[i+1][j+1]=max(f[i+1][j+1],f[i][j]-a[i+1].a);
			}
		}
		if(f[i+1][ans+1]>=0) ans++;
	}
	printf("%d\n",ans);
}

BZOJ_3174_[Tjoi2013]拯救小矮人_貪心+DP