P2577 [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的正整数。


先按照吃饭时间排序,然后用\(f[i][j]\)表示前\(i\)个人拍成的队打饭时间相差为\(j\)时最的吃饭时间。
这时由于打饭总时长是一定的,打饭时间较长的队的打饭时间为\((sum+j)/2\),打饭时间较短的队的打饭时间为\((sum-j)/2\) 状态转移就是把一个人放在较长队或较短队然后把总时间和元最大值比较即可


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;
struct vv
{
    int d,e;
} a[100001];
int i,m,n,j,k,f[201][80001],ans=0x3f3f3f3f;

bool cmp(vv a,vv b)
{
    return a.e>b.e; 
}

int main()
{
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d%d",&a[i].d,&a[i].e);
    memset(f,0x3f,sizeof(f));
    sort(a+1,a+1+n,cmp);
    f[0][0]=0;
    for(i=1;i<=n;i++)
    {
        m+=a[i].d;
        for(j=0;j<=m;j++)
        {
            if(f[i-1][abs(j-a[i].d)]<0x3f3f3f3f) 
            f[i][j]=min(f[i][j],max(f[i-1][abs(j-a[i].d)],(m+j)/2+a[i].e)); 
            if(f[i-1][j+a[i].d]<0x3f3f3f3f)
            f[i][j]=min(f[i][j],max(f[i-1][j+a[i].d],(m-j)/2+a[i].e));
        }
    }
    for(i=0;i<=m;i++)
        ans=min(ans,f[n][i]);
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/ZUTTER/p/9561159.html
今日推荐