1. 程式人生 > >[BZOJ1899]Lunch 午餐(DP)

[BZOJ1899]Lunch 午餐(DP)

print 前綴 zoj div IE || sort operator while

[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;
}

[BZOJ1899]Lunch 午餐(DP)