【简●解】[ZJOI2005]午餐

【简●解】[ZJOI2005]午餐


【关键词】

  • \(DP\)
  • 排序/贪心

【分析】

首先,一个很明显的贪心思路,就是吃的慢的人先打饭。所以把数据按吃饭时间从大到小排一遍序。

根据\(dp\)的尿性,比较容易想到一个\(dp\)方程\(f[i][j][k]\):前\(i\)个人,在一号窗口打饭总时间为\(j\),在二号窗口打饭总时间为\(k\)的最早集合时间。

然后转移。。。

从方程中就可以看出,这爆空间了啊。

所以优化。

我们可以发现,\(j+k=\)\(i\)个人打饭时间总和,所以\(k=sum(i)-j\),所以维护下打饭时间的前缀和就行了,于是,我们就可以去掉一维:
f[i][j]表示前i个人,在一号窗口打饭总时间\(j\),最早集合的时间

那么每次转移有两种决策。

  1. 将第\(i\)个人放在一号窗口,即: \(max(f[i-1][j-s[i].wait], j+s[i].eat)\)
  2. 将第\(i\)个人放在二号窗口,即: \(max(f[i-1][j], sum[i]-j+s[i].eat)\)

然后取个最小值,输出,完事。

【Code】

//#include<bits/stdc++.h>
#pragma GCC optimize("O3")
#pragma GCC optimize("O2")
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug() puts("FBI WARNING!")
#define R register
#define I inline
using namespace std;
const int MAX = 200 + 5; 
inline int read(){
    int f = 1, x = 0;char ch;
    do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0'||ch>'9');
    do {x = x*10+ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); 
    return f*x;
}
int n, sum[MAX], f[MAX][MAX * MAX], ans = 0x7ffffff;
struct sakura {
    int eat, wait;
}sak[MAX]; 
inline bool cmp(const sakura &a, const sakura &b) {
    return a.eat > b.eat;
} 
int main(){
    n = read();
    for (R int i = 1;i <= n; ++i) {
        sak[i].wait = read(), sak[i].eat = read();
    }   
    memset(f, 127, sizeof (f));
    f[0][0] = 0;
    sort(sak + 1, sak + 1 + n, cmp);
    for (int i = 1;i <= n; ++i) sum[i] = sum[i - 1] + sak[i].wait;
    for (int i = 1;i <= n; ++i) {
        for (int j = 0;j <= sum[i]; ++j) {
            if (j >= sak[i].wait) {
                f[i][j] = min(f[i][j], max(f[i-1][j-sak[i].wait], j+sak[i].eat));
            }
                f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+sak[i].eat));
        }
    }
    for (int i = 0;i <= sum[n]; ++i) {
        ans = min(ans, f[n][i]);
    }
    printf("%d", ans);
    return 0;
}

转载于:https://www.cnblogs.com/silentEAG/p/10718435.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值