题目:传送门。
这个是DP,比赛的时候用贪心写了好久没写出来。
题意:
有n个矮人被困在深度为h的井中,每个矮人都ai(脚到肩膀的高度)和bi(手臂长度), 当存在a1 + a2 + ... + ak-1 + ak+ bk >= h,矮人k可以从井中逃脱出去。问最多能逃出去几个人。
题解:
dp[i][j]代表的是在前i个人中能逃脱出j个人后,剩余井中矮人再想逃脱出至少一人还需要的最小高度是多少,分析如下,逃脱出的j个人中最后逃脱的一定是 ai +bi最大的,这样才能得到dp值是最优的,需要首先对矮人按照ai + bi从大到小排序,考虑当前第i个人可以逃脱可以不逃脱,即dp[i][j]只可能由两种情况得来:
dp[i-1][j]:i位置的人没逃脱出去,所以所需的高度就是dp[i-1][j] - a[i]。
dp[i-1][j-1]:i位置的人逃脱出去了,所需高度有两种情况:
1 i的身高和臂长之和足够大,利用之前所需高度就可以逃脱,这时所需高度是dp[i-1][j-1];
2 i的身高和臂长之和不够大,此时i最先逃脱,所以需要的高度就是前i-1个人帮助i逃脱,所需高度是H -sumA[i] - b[i]。
以上两种情况必须都满足才能得到dp[i][j],所以需要取最大值,
综上得dp方程:dp[i][j] = MIN(dp[i-1][j] - dwarf[i].a , MAX(dp[i-1][j-1] , h - sum[i] -dwarf[i].b));
#include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> #define MIN(a , b) ((a) < (b) ? (a) : (b)) #define MAX(a , b) ((a) > (b) ? (a) : (b)) using namespace std; const int inf = 1 << 29; const int maxn = 2002; struct D { int a,b; bool operator < (const D &other) const { return a + b > other.a + other.b; } }dwarf[maxn]; int sum[maxn],dp[maxn][maxn]; int n,h; void read() { memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { scanf("%d %d",&dwarf[i].a,&dwarf[i].b); } scanf("%d",&h); sort(dwarf + 1 , dwarf + n + 1); sum[0] = 0; for(int i=1;i<=n;i++) { sum[i] = sum[i-1] + dwarf[i].a; } for(int i=0;i<=n;i++) { for(int j=i+1;j<=n;j++) { dp[i][j] = inf; } } return; } void solve() { for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { dp[i][j] = MIN(dp[i-1][j] - dwarf[i].a , MAX(dp[i-1][j-1] , h - sum[i] - dwarf[i].b)); } } for(int i=n;i>=0;i--) { if(dp[n][i] <= 0) { printf("%d ",i); break; } } return; } int main() { while(~scanf("%d",&n)) { read(); solve(); } return 0; }