午餐
作者:互联网
其实排队没有问题,很容易想到先按照吃饭时间排序,那么接下来的操作就很玄学了,我先想到的是吧他们分成两组,就相当于一个背包,但是因为背包容量实在是太大了,我们考虑优化,因为前 ii 个人打饭的总时间相同,那么总时间就是固定的,所以我们记录第一个窗口就 OK 了,第二个窗口就是 sum[i]-j ;
状态:
f[i][j]f[i][j] 表示第i个人,一共打了j个时间,花费的时间
转移
1.放在1号窗口,先要能打饭
if(j>=x[i].a)f[i][j]=min(f[i][j],max(f[i-1][j-x[i].a],j+x[i].b)) //窗口打饭的时间加上吃饭的时间
2.放在2号窗口
f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+x[i].b); //打饭的时间加上吃饭的时间
Code
#include<bits/stdc++.h> #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) using namespace std; int n,sum[205],f[205][40005]; struct node{int a,b;}x[205]; bool cmp(node a,node b){return a.b>b.b;} int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d%d",&x[i].a,&x[i].b); memset(f,0x3f,sizeof(f)); f[0][0]=0; sort(x+1,x+n+1,cmp); for(int i=1;i<=n;++i)sum[i]=sum[i-1]+x[i].a;//记录前缀和 for(int i=1;i<=n;++i) for(int j=0;j<=sum[i];++j){//记得从0开始 if(j>=x[i].a)f[i][j]=min(f[i][j],max(f[i-1][j-x[i].a],j+x[i].b));//第一种转移 f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+x[i].b));//第二种转移 } int ans=1e9; for(int i=0;i<=sum[n];++i)ans=min(ans,f[n][i]); cout<<ans; }
标签:窗口,min,int,max,午餐,打饭,sum 来源: https://www.cnblogs.com/coder-cjh/p/11674379.html