1 条题解

  • 0
    @ 2025-8-24 21:39:16

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar M_seа
    **

    搬运于2025-08-24 21:39:16,当前版本为作者最后更新于2018-02-21 17:35:45,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    原文

    这道题目比较难想。

    算法:贪心+dp

    容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序。

    然后就是dp了: 首先,应该想到f[i][j][k]:前i个人,在1号窗口打饭总时间j,在2号窗口打饭总时间k

    当然,这样会爆空间,所以想到去掉一维。

    f[i][j]表示前i个人,在1号窗口打饭总时间j,最早吃完饭的时间

    我们可以发现 j+k=前i个人打饭总和,k = sum(i)-j。 所以可以维护一个前缀和:

    for(int i = 1; i <= n; i++)
    	sum[i] = sum[i-1] + s[i].a;
    

    接下来就是dp的转移:

    将第i个人放在1号窗口:
    if(j>=s[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-s[i].a], j+s[i].b));
    
    f[i-1][j-s[i].a]是i号人打饭+吃饭的时间不足i-1号人吃饭的时间, 所以没有影响
    j+s[i].b就是造成了影响
    
    将第i个人放在2号窗口:
    f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+s[i].b));   
    这里也是一样的 
    (sum[i]-j 就是k)
    

    转移方程如果没有看懂,可以结合图来理解

    完整代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 210;
    int f[N][N*N];
    struct node
    {
        int a, b;
        bool operator <(node z) const
        {
            return b>z.b;
        }
    }s[N];
    int sum[N];
    int main()
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d %d", &s[i].a, &s[i].b);
        sort(s+1, s+1+n);
        for(int i = 1; i <= n; i++)
            sum[i] = sum[i-1] + s[i].a;
        memset(f, 127, sizeof(f));
        f[0][0] = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= sum[i]; j++)
            {
                if(j>=s[i].a) f[i][j] = min(f[i][j], max(f[i-1][j-s[i].a], j+s[i].b));
                f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+s[i].b));
            }
        }
        int ans = 2147483647;
        for(int i = 0; i <= sum[n]; i++)
            ans = min(ans, f[n][i]);
        printf("%d\n", ans);
        return 0;
    }
    
    • 1

    信息

    ID
    1615
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者