[BZOJ1899]Lunch 午餐(DP)

[BZOJ1899]

首先有个很贪心的思路,吃饭时间长的最先打饭为最优,所以开始先排个序

然后考虑DP,我们不需要知道某个人在哪个对,只要关注总的时间就行了

肯定需要一维表示当前同学编号,还需要表示某个窗口的打饭时间,如果知道其中一个窗口,另一个也可以知道,所以一维就行

那么用f[i][j]表示前i个同学,第一个窗口打饭总时间为j时的答案

s[i]表示排序后前打饭时间前缀和,a表示打饭时间,b表示吃饭时间

  1. 当前同学放二号窗口,f[i][j]=min{f[i][j],max(f[i-1][j],sum[i-1]-j+A[i].a+A[i].b)}
  2. 放1号窗口,f[i][j]=min{f[i][j],max(f[i-1][j-A[i].a],j+A[i].b)}

Code

 

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 210 
using namespace std;

struct info{
	int a,b;
	friend bool operator <(info a,info b){
		return a.b>b.b;
	}
}A[N];
int n,Ans,s[N],f[N][N*N],sum;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int main(){
	n=read();
	for(int i=1;i<=n;++i) A[i].a=read(),A[i].b=read();
	sort(A+1,A+n+1);
	for(int i=1;i<=n;++i) s[i]=s[i-1]+A[i].a;
	memset(f,0x3f,sizeof(f));f[0][0]=0;
	for(int i=1;i<=n;++i)
		for(int j=0;j<=s[i];++j){
			f[i][j]=min(f[i][j],max(f[i-1][j],s[i-1]-j+A[i].a+A[i].b));
			if(j>=A[i].a) f[i][j]=min(f[i][j],max(f[i-1][j-A[i].a],j+A[i].b));
		}
	Ans=1e9;
	for(int i=0;i<=s[n];++i) Ans=min(Ans,f[n][i]);
	printf("%d\n",Ans);
	return 0;
}

 

posted @ 2018-05-11 16:52  void_f  阅读(147)  评论(0编辑  收藏  举报