[ZJOI2005]午餐

题目描述

上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。

THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。

现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。

假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。

现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。

输入格式

第一行一个整数N,代表总共有N个人。

以下N行,每行两个整数 Ai,Bi。依次代表第i个人的打饭时间和吃饭时间。

输出格式

一个整数T,代表所有人吃完饭的最早时刻。

所有输入数据均为不超过200的正整数。


容易想到的一个贪心策略就是:让打饭慢的人先打饭。所以我们一开始可以对所有人按照打饭时间排序。

然后我们开始考虑窗口的选择。显然,前i个人的最优解一定是由前i-1个人的最优解更新而来的,所以我们可以考虑用动态规划。考虑第i个人怎么选窗口会最优。

第i个人选窗口会影响到的因素就是:在1窗口打饭一共用了多少时间、在2窗口打饭一共用了多少时间。那么我们把这两个量设计进状态即可。设dp[i][j][k]表示前i个人在1窗口用了j个单位时间、在2窗口用了k个单位时间的情况下,前i个人吃完饭的最早时刻。

那么转移很好想,O(1)转移即可。但是进一步分析会发现一个问题:j和k的上限为\(200*200=40000\),这样开数组肯定会爆的...那么想一想优化。

可以发现j和k加起来刚好等于前i个人的打饭时间和。那么换个思路,我们求出前i个人的打饭时间和sum[i],那么我们只需要知道j就可以求出k了。那么我们的状态就可以省掉一维:dp[i][j]表示前i个人在1号窗口用了j个单位时间的情况下,前i个人吃完饭的最早时刻。可以得出转移方程:

\[
dp[i][j]=
\left\{ \begin{array}{rcl}
min(max(dp[i-1][j-p[i].a],j+p[i].b),max(dp[i-1][j],k+p[i].b)) & j,k>=a[i]\max(dp[i-1][j-p[i].a],j+p[i].b) & j>=a[i]\max(dp[i-1][j],k+p[i].b) & k>=a[i]
\end{array}\right.
\]

初始化\(dp[i][j]=inf\),\(dp[0][0]=0\)。答案就是\(Max{\{}dp[n][i]{\}}\)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 201
#define maxm 40001
#define inf 0x3f3f3f3f
using namespace std;

inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

struct node{ int a,b; }p[maxn];
int dp[maxn][maxm];
int n,c[maxn];

inline bool cmp(const node &x,const node &y){ return x.b>y.b; }
int main(){
    n=read();
    for(register int i=1;i<=n;i++) p[i].a=read(),p[i].b=read();

    sort(p+1,p+1+n,cmp);
    for(register int i=1;i<=n;i++) c[i]=c[i-1]+p[i].a;

    memset(dp,0x3f,sizeof dp),dp[0][0]=0;
    for(register int i=1;i<=n;i++){
        for(register int j=0;j<=c[i];j++){
            register int k=c[i]-j;
            if(j>=p[i].a && k>=p[i].a) dp[i][j]=min( max( dp[i-1][j-p[i].a],j+p[i].b ),max( dp[i-1][j],k+p[i].b ) );
            else if(j>=p[i].a) dp[i][j]=max( dp[i-1][j-p[i].a],j+p[i].b );
            else if(k>=p[i].a) dp[i][j]=max( dp[i-1][j],k+p[i].b );
        }
    }

    int ans=inf;
    for(register int i=0;i<=c[n];i++) ans=min( ans,dp[n][i] );
    printf("%d\n",ans);
    return 0;
}

时间复杂度为\(O(N*40000)\)

原文地址:https://www.cnblogs.com/akura/p/11287014.html

时间: 2024-10-10 11:42:51

[ZJOI2005]午餐的相关文章

ZJOI2005午餐

描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的.另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的. THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭.每个人打完饭后立刻开始吃,所有人都吃完

[ZJOI2005]午餐 (贪心,动态规划)

题目描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的.另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的. THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭.每个人打完饭后立刻开始吃,所有人都

P2577 [ZJOI2005]午餐

题目描述 上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭.由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的.另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的. THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭.每个人打完饭后立刻开始吃,所有人都

[luoguP2577] [ZJOI2005]午餐(DP)

传送门 显然吃饭时间越长的人排在前面越好,所以先排序. f[i][j]表示前i个人,A队的打饭时间为j的最优解,每个人只有两种选择,去A队或是去B队. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 201 #define max(x, y) ((x) > (y) ? (x) : (y)) #define min(x, y)

我不想写题解的题们

[NOI2004]起床困难综合征:预处理每一位用1好还是0好,按位贪心就行. [网络流24题]运输问题:最小费用最大流裸题,最大费用权值取反就行.(然后我spfa就写错了) [ZJOI2005]午餐:排序后DP就行. [USACO08OCT]WateringHole:Prim板子. [SDOI2009]HH去散步:矩阵优化DP. [国家集训队]小Z的袜子:莫队. [HNOI2008]弹飞绵羊:分块,维护某个点几步出块和出块后到哪个点. [Luogu]教主的魔法:分块. 原文地址:https://

【ZJOI2005】午餐

题面 https://www.luogu.org/problem/P2577 题解 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; struct node{ int a,b; bool operator < (const node &rhs) const { return b>rhs.b; } }

【BZOJ1898】[Zjoi2005]Swamp 沼泽鳄鱼 矩阵乘法

[BZOJ1898][Zjoi2005]Swamp 沼泽鳄鱼 Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石桥.这个景点造好之后一直没敢对外开放,原因是池塘里有不少危险的食人鱼.豆豆先生酷爱冒险,他一听说这个消息,立马赶到了池塘,想做第一个在桥上旅游的人.虽说豆豆爱冒险,但也不

微服务架构——不是免费的午餐

当我開始了解<微服务架构>的时候,我发现里面的中文文章是相当的少,于是開始试着翻译一些文章,比方这一篇<微服务--不是免费的午餐>.这篇文章是在某次讨论结束后听到的,和之前相似的是这样的差别有点相似于之前说的微内核与宏内核的差别. 译文例如以下: 文章是由Contino公司的CTO,Benjamin Wootton写的.Contino是一家在伦敦的咨询公司,专注于DevOps和持续支付. Microservices are a style of software architect

Unit 05 受邀与同事共进午餐

单词 restaurant    餐厅 yet           还(未) dinner        主餐 bother        麻烦 pleasure      快乐 tomato        西红柿 either        也 project       工程 know          知道 follow        跟随 trifle        琐事 waste         浪费 ashamed       害羞的 roughly       大致地 conce