BZOJ 1899 午餐 (洛谷P2577)

DP

Description

上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。 THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。 现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。 假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。 现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
Input

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

一个整数T,代表所有人吃完饭的最早时刻。
Sample Input
5
2 2
7 7
1 3
6 4
8 5

Sample Output
17

HINT
方案如下:
窗口1: 窗口2:
7 7 ———1 3
6 4 ———8 5
2 2

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

比较难想的一道DP(或者是我太菜)
先以b为关键字排序(降序),f[i][j]表示一号窗口前i人等候时间为j时的最优值。
很神奇。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[205][3],n,f[205][40005],b[205];
void kp(int l,int r)
{
    int p,q,mid;
    p=l;q=r;
    mid=a[(p+q)/2][2];
    while (p<=q)
        {
            while (a[p][2]>mid) p++;
            while (a[q][2]<mid) q--;
            if (p<=q)
                {
                    swap(a[p][2],a[q][2]);
                    swap(a[p][1],a[q][1]);
                    p++; q--;
                }
        }
    if (p<r) kp(p,r);
    if (l<q) kp(l,q);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i][1],&a[i][2]);
    kp(1,n);
    for (int i=1;i<=n;i++)
        b[i]=b[i-1]+a[i][1];
    memset(f,0x7f,sizeof(f));
    f[0][0]=0;
    for (int i=1;i<=n;i++)
        for (int j=0;j<=b[i-1];j++)
            {
                f[i][j]=min(f[i][j],max(f[i-1][j],b[i-1]-j+a[i][1]+a[i][2]));
                f[i][j+a[i][1]]=min(f[i][j+a[i][1]],max(f[i-1][j],j+a[i][1]+a[i][2]));
            }
    int ans=0x7fffffff;
    for (int i=0;i<=b[n];i++)
        ans=min(ans,f[n][i]);
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值