午餐

其实排队没有问题,很容易想到先按照吃饭时间排序,那么接下来的操作就很玄学了,我先想到的是吧他们分成两组,就相当于一个背包,但是因为背包容量实在是太大了,我们考虑优化,因为前 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;
}

 

 

猜你喜欢

转载自www.cnblogs.com/coder-cjh/p/11674379.html
今日推荐