zoukankan      html  css  js  c++  java
  • BZOJ1899 [Zjoi2004]Lunch 午餐 贪心+DP

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=1899

    题解

    如果只有一个窗口,那么可以这样考虑:因为最后一个人打完饭的时间是固定的,那么不如就让吃饭最快的人最后打完。然后以此类推到前 (n-1) 个人……最终可以得出把所有的人的吃饭时间倒序排序以后打饭最优。

    但是,如果有两个窗口,那么一开始的大前提“最后一个人打完饭的时间是固定的”就不对了。(为了想为什么两个窗口就不对想了两节课)

    不过我们可以发现,如果把两个窗口单独考虑,各自也还应该是按吃饭时间倒序排序的。因此我们可以先把所有人按照吃饭时间倒序排序以后来分配窗口。

    我们发现对于第 (i) 个人,只需要知道前 (i-1) 个人中,在其中一个窗口打饭的总时间就可以算出当前的第 (i) 个人在每个窗口打饭时最终所需的时间。

    因此考虑 dp,令 (dp[i][j]) 表示前 (i) 个人中在第一个窗口打饭的总时间为 (j) 时,前 (i) 个人吃完饭的最大的时间。

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I>
    inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 200 + 7;
    const int M = 200 * 200 + 7;
    
    int n;
    int s[N], dp[N][M];
    
    struct Wph { int a, b; } a[N];
    inline bool operator < (const Wph &p, const Wph &q) { return p.b > q.b; }
    
    inline void work() {
    	for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i].a;
    	memset(dp, 0x3f, sizeof(dp)), dp[0][0] = 0;
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 0; j <= s[i]; ++j) {
    			dp[i][j] = std::max(dp[i - 1][j], s[i] - j + a[i].b);
    			if (j >= a[i].a) smin(dp[i][j], std::max(dp[i - 1][j - a[i].a], j + a[i].b));
    		}
    	}
    	int ans = s[n] + a[n].b;
    	for (int i = 0; i <= s[n]; ++i) smin(ans, dp[n][i]);
    	printf("%d
    ", ans);
    }
    
    inline void init() {
    	read(n);
    	for (int i = 1; i <= n; ++i) read(a[i].a), read(a[i].b);
    	std::sort(a + 1, a + n + 1);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    5.4 省选模拟赛 修改 线段树优化dp 线段树上二分
    一本通 高手训练 1782 分层图 状压dp
    luogu P3830 [SHOI2012]随机树 期望 dp
    5.2 省选模拟赛 或许 线型基
    luogu P4562 [JXOI2018]游戏 组合数学
    一本通 高手训练 1781 死亡之树 状态压缩dp
    luogu P4726 【模板】多项式指数函数 多项式 exp 牛顿迭代 泰勒展开
    4.28 省选模拟赛 负环 倍增 矩阵乘法 dp
    HDU 1756 Cupid's Arrow 计算几何 判断一个点是否在多边形内
    一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ1899.html
Copyright © 2011-2022 走看看