午餐
其实排队没有问题,很容易想到先按照吃饭时间排序,那么接下来的操作就很玄学了,我先想到的是吧他们分成两组,就相当于一个背包,但是因为背包容量实在是太大了,我们考虑优化,因为前 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; }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步