bzoj3174 拯救小矮人 题解报告

题目传送门

【题目大意】

有$n$个小矮人掉进洞里,第$i$个小矮人的身高为$a_i$,臂长为$b_i$,洞的深度为$H$。小矮人可以叠在一起让更多人出去,叠在一起的所有小矮人的身高加上最上面的小矮人的臂长如果不小于$H$,那么最上面的小矮人就可以逃出去,求最多有多少个小矮人能逃出去。

【思路分析】

首先看到问题求最多,那么很容易想到$dp$,于是我们设$f[i][j]$表示到第$i$个小矮人,已经逃出去了$j$个的最大高度。

转移方程:$f[i][j+1]=max(f[i][j+1],f[i][j]-a[i])(0\le j\le ans)$,其中$ans$表示最多已经逃出去的小矮人数量。

初始化:$f[0]=\sum_{i=1}^{n}a[i]$,其余$f=-1$

最后的答案为$ans$

但是我们还要考虑$i$扫过每个小矮人的顺序,于是想到贪心

对于$a+b$更大的小矮人,他逃出去的可能性也更大,即他可以排在后面逃出去,所以我们按照$a+b$的值给小矮人从小到大排序,然后再$dp$

【代码实现】

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define g() getchar()
 7 #define rg register
 8 #define go(i,a,b) for(rg int i=a;i<=b;i++)
 9 #define back(i,a,b) for(rg int i=a;i>=b;i--)
10 #define db double
11 #define ll long long
12 #define il inline
13 #define pf printf
14 #define mem(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 int fr(){
17     int w=0,q=1;
18     char ch=g();
19     while(ch<'0'||ch>'9'){
20         if(ch=='-') q=-1;
21         ch=g();
22     }
23     while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
24     return w*q;
25 }
26 const int N=2002;
27 int n,h,f[N],ans;
28 struct dolf{
29     int a,b,sum;
30 }df[N];
31 il bool cmp(dolf x,dolf y){
32     if(x.sum==y.sum) return x.a<y.a;
33     return x.sum<y.sum;
34 }
35 int main(){
36     //freopen("","r",stdin);
37     //freopen("","w",stdout);
38     n=fr();mem(f,-1);f[0]=0;
39     go(i,1,n) df[i].a=fr(),df[i].b=fr(),df[i].sum=df[i].a+df[i].b,f[0]+=df[i].a;
40     h=fr();sort(df+1,df+1+n,cmp);
41     go(i,1,n){
42         back(j,ans,0) if(f[j]+df[i].b>=h) f[j+1]=max(f[j+1],f[j]-df[i].a);
43         //保证当前这个小矮人i能逃出去    
44         if(f[ans+1]>=0) ans++;
45     }
46     pf("%d\n",ans);
47     return 0;
48 }
代码戳这里
posted @ 2019-09-18 22:09  小叽居biubiu  阅读(250)  评论(1编辑  收藏  举报