P2577 [ZJOI2005]午餐 - 贪心 - dp

49 篇文章 0 订阅
13 篇文章 0 订阅

首先考虑只放一队的情况,显然是吃饭时间长的优先打饭,然而我没这么想直接套了国王游戏的模型,事实上还是从别的角度多想想比较好
然后是dp,这道题怎么安排人到不同的窗口很难说,所以考虑用最暴力的状态和转移(反正数据范围小)
设f[i][j][k]表示安排了前i人,第一个窗口的打饭总时间为j,第二个窗口打饭总时间为k,最优集合时间是多少
然后决策一下每个人在哪打饭,并且注意一下答案的更新
但是会爆内存,考虑到j和k其实是唯一对应的,可以省去一维,设sum[i]为前i个人打饭时间之和,那么k = sum[i] - j,因此可以直接算出k,没必要多开一维
转移时注意前面的人吃饭时间可能比一个之后打饭的人吃完还慢

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200 + 10;
struct lunch{
	int a, b;
}lun[MAXN];
int n,ans=1<<30,f[MAXN][40000 + 10],sum[MAXN];
bool cmp(lunch a, lunch b) {
	//return a.b > b.b; 
	int ai = a.a, bi = a.b, aj = b.a, bj = b.b;
	return max(ai+bi, ai+aj+bj) < max(aj+bj, aj+ai+bi);
} 
int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) {
		scanf("%d%d", &lun[i].a, &lun[i].b);
	}
	sort(lun+1, lun+n+1, cmp);
	for(int i=1; i<=n; i++) {
		sum[i] = sum[i-1] + lun[i].a;
	}
	memset(f, 0x3f, sizeof(f));
	f[0][0] = 0;
	for(int i=1; i<=n; i++) {
		for(int j=0; j<=sum[i]; j++) {
			if(j >= lun[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-lun[i].a], j+lun[i].b));
			f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+lun[i].b));
		}
	}
	for(int i=0; i<=sum[n]; i++) {
		ans = min(ans, f[n][i]);
	}
	printf("%d", ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值