洛谷P2577 [zjoi2004]午餐---贪心+dp

题目链接:https://www.luogu.com.cn/problem/P2577

简单题意:两个窗口打饭,每个人有打饭和吃饭时间,求最快全部吃完的时间

让吃饭时间长的先打饭,应该比较容易想到,不管窗口数量是多少。但是之后就开始胡乱设计状态了。一开始想了个sb状态:dp[i][1/2]表示轮到第i个人,选择窗口1/2的最小时间,发现根本写不出来方程......

正解是设 f[i][j]表示前i个人在窗口1打饭时间为j,吃完饭的最早时间。有点难想到,而且这个状态怎么只考虑了一个窗口?其实原方程是 f[i][j][k]表示前i个人,在1窗口打饭时间为j,2窗口为k的最早时间,由于j+k是定值,所以可以去掉一维。转移方程看代码吧,其实有点像个背包问题(细节:有可能第i个人吃完饭了,之前的人还没吃完)。另外这个初始化纠结了一会,一开始总是想前i个人如果打饭时间不能为j怎么办,其实全初始化为inf就行了

#include<bits/stdc++.h>
#define ll long long 
using namespace std;

struct st{int c,d;}a[210];
int n,i,j,k,ans,f[210][210*210],sum[210];
bool cmp(st p,st q){return p.c>q.c;}
//f[i][j]: 前i个人在窗口1打饭时间为j的最小结束时间 

int main(){
	cin>>n;
	for (i=1;i<=n;i++) cin>>a[i].d>>a[i].c;
	sort(a+1,a+n+1,cmp); //吃饭时间降序 
	for (i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].d;
	memset(f,0x3f,sizeof(f)); f[0][0]=0; //*
	for (i=1;i<=n;i++)
	  for (j=0;j<=sum[i];j++){
	  	if (j-a[i].d>=0) f[i][j]=max(j+a[i].c,f[i-1][j-a[i].d]); //i放在队1 
	  	f[i][j]=min(f[i][j],max(sum[i]-j+a[i].c,f[i-1][j]));  //i放在队2 
	  }
	ans=1e9;
	for (i=0;i<=sum[n];i++) ans=min(ans,f[n][i]);
	cout<<ans<<endl;
	return 0;
}

  

原文地址:https://www.cnblogs.com/edmunds/p/13423744.html