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

题目描述

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

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

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

输入输出样例

输入样例#1:

5
2 2
7 7
1 3
6 4
8 5

输出样例#1:

17

说明

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


Solution

考虑贪心.


给出贪心条件证明:
令当前,有两个人分别为 a,b,且满足 a 在 b 前为更优解.
排队和吃饭时间分别为:
\[d_a,c_a,d_b,c_b\]
那么当前如果 a 在 b前,所需要花费的时间即为:
\[d_a+max(c_a,d_b+c_b)\]

同理,如果 b 在 a 前,所需花费的时间为:
\[d_b+max(c_b,d_a+c_a)\]

因为满足 a 在 b 前条件更优,即满足关系:
\[d_a+max(c_a,d_b+c_b)<d_b+max(c_b,d_a+c_a)\]


以上贪心是一列队的做法,对于两列,考虑DP.
定义状态:
\[f[i][j]\]
表示到了第 i 个人,第1队打饭时间 (不包括吃饭)为 j 时的最小集合时间.

转移方程
对于第 i 个人,它有两种情况.
1) 去第一队
\[f[i+1][j+a[i+1].w]=min(f[i+1][j+a[i+1].d],max(j+a[i+1].d+a[i+1].c,f[i][j]));\]
2) 去第二队
\[f[i+1][j]=min(f[i+1][j],max(f[i][j],a[i+1].c+sum[i]-j+a[i+1].d));\]

其中 sum 代表排序之后的排队前缀和.

#include<bits/stdc++.h>
using namespace std;
const int maxn=208;
struct sj{
    int c;
    int d;
}a[maxn];
bool cmp(sj s,sj j)
{return s.d+max(s.c,j.c+j.d)<j.d+max(j.c,s.c+s.d);}

int n,sum[maxn];
int f[maxn][maxn*maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>a[i].d>>a[i].c;
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    sum[i]=sum[i-1]+a[i].d;
    memset(f,127,sizeof(f));
    int inf=f[0][0];
    f[0][0]=0;
    for(int i=0;i<n;i++)
    for(int j=0;j<=sum[i];j++)
    {
        if(f[i][j]==inf)
        continue;
        f[i+1][j+a[i+1].d]=min(f[i+1][j+a[i+1].d],max(j+a[i+1].d+a[i+1].c,f[i][j]));
        f[i+1][j]=min(f[i+1][j],max(f[i][j],a[i+1].c+sum[i]-j+a[i+1].d));
    }
    int ans=19260817;
    for(int i=0;i<=sum[n];i++)
    ans=min(ans,f[n][i]);
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/Kv-Stalin/p/9193539.html

时间: 2024-07-30 15:36:32

[ZJOI2005]午餐 (贪心,动态规划)的相关文章

贪心 &amp; 动态规划

相同点: 贪心算法和dp都是一种递推算法,是一种解题的思想 都是由局部最优解来推导全局最优解 不同点: 贪心算法: 1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留. 2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解 3.求最小生成树的Prim算法和Kruskal算法都是漂亮的贪心算法.背包问题. 动态规划: 1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因

【BZOJ1899】午餐(动态规划)

[BZOJ1899]午餐(动态规划) 题面 BZOJ 题解 我太弱了 这种\(dp\)完全做不动.. 首先,感性理解一些 如果所有人都要早点走, 那么,吃饭时间长的就先吃 吃饭时间短的就晚点吃 所以,按照吃饭时间排序 我们不难得出一个每个人吃完饭的时间 之和前面所有人的打饭的时间和有关 所以 \(f[i][j][k]\)表示当前做到第\(i\)个人,第一列,第二列前面的人的打饭时间之和分别为\(j,k\)时,最后一个人吃完饭的最小时间 因为人的顺序我们是知道的 所以\(j+k\)是一个定值,是所

ZJOI2005午餐

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

[ZJOI2005]午餐

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

P2577 [ZJOI2005]午餐

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

【BZOJ1899】[Zjoi2004]Lunch 午餐 贪心+DP

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

codeforces 某套题s : surf(贪心 || 动态规划)

题目: Now that you've come to Florida and taken up surfing, you love it! Of course, you've realized that if you take a particular wave, even if it's very fun, you may miss another wave that's just about to come that's even more fun. Luckily, you've got

[SCOI2008]配对 (贪心,动态规划)

题目链接 Solution 很妙的DP,很妙的贪心. 首先考虑,如果说没有那个相同的不能配对的情况; 那么我们肯定是直接排两遍序,然后一一对应即可. 但是是有限制的,同时我们可得几个条件供贪心: 每个数字仅在 \(a\) 或 \(b\) 中出现一次. 即每个序列排序之后满足 \(a_i≠b_i\). 如果 \(a_i=b_i\) ,我们需要去和其他位置的元素交换; 我们交换的元素与当前元素的绝对距离不会大于 \(2\),也就是说每次我们碰到相同的情况,只需要 \(a_i\) 与 \(a_{i+1

[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)