洛谷P2577 [ZJOI2005]午餐

挺棒的一道dp。

贪心策略容易想到。直接按吃饭时间从大到小排序即可。

重点是dp。可以设方程为 f[前 i 人] [ 队列1的时间 j ] 然后加上一个常见的滚动数组套路。

方程的转移还是很有意思。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 200 + 10;

struct People
{
    int a, b;
    bool operator >(const People &rhs) const{
        return b > rhs.b;
    }
}pe[MAXN];

int N;
int f[2][MAXN * MAXN];
int sum[MAXN];

int main()
{   
    cin>>N;
    for(int i = 1; i <= N; i++)
        scanf("%d%d", &pe[i].a, &pe[i].b);
    sort(pe + 1, pe + N + 1, greater<People>());
    for(int i = 1; i <= N; i++) sum[i] = sum[i - 1] + pe[i].a;
    memset(f, 0x3f, sizeof(f)); 

    int tmp = 0, d = 0; f[d][0] = 0;
    for(int i = 1; i <= N; i++){
        d ^= 1; memset(f[d], 0x3f, sizeof(f[d]));
        for(int j = 0; j <= tmp; j++){
            f[d][j + pe[i].a] = min(f[d][j + pe[i].a], max(f[d ^ 1][j], j + pe[i].a + pe[i].b));
            f[d][j] = min(f[d][j], max(f[d ^ 1][j], sum[i] - j + pe[i].b));
        }
        tmp += pe[i].a;
    }
    
    int ans = (1 << 29);
    for(int i = 0; i <= tmp; i++) ans = min(ans, f[d][i]);
    cout<<ans;
    return 0;
}

 

posted @ 2018-07-16 20:23  俺是小程  阅读(112)  评论(0编辑  收藏  举报