1 条题解

  • 0
    @ 2025-8-24 21:33:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 冈崎梦美
    **

    搬运于2025-08-24 21:33:35,当前版本为作者最后更新于2017-12-20 23:47:15,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    一道经典的区间DP练习题。

    设f[i][j]为前i个公司总共分配j台机器的最大利润。对于第i家子公司,我们可以给其分配的机器台数为:

    0,1,2……m

    所以在该区间内枚举一个值k,状态转移方程即为:

    f[i][j]=max(f[i-1][j-k],f[i][j]);

    那么,如何处理方案输出问题呢?

    我们设path[i][j][h]对于前i个公司共分配j台机器的最优方案,第h个公司应分配多少台机器,当状态发生转移时,更新path数组即可。最终的答案就存放在path[n][m][i]之中。

    贴代码:

    #include<bits/stdc++.h>
    using namespace std;
    int f[11][16],graph[11][16],path[11][16][11],n,m;
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cin>>graph[i][j];
        }
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)    
                for(int k=0;k<=j;k++)
                {
                    if (f[i][j]<f[i-1][j-k]+graph[i][k])
                    {
                        f[i][j]=f[i-1][j-k]+graph[i][k];
                        for(int h=1;h<i;h++) path[i][j][h]=path[i-1][j-k][h];//path数组只有在状态发生转移时才更新
                        path[i][j][i]=k;
                    }    
                }
        cout<<f[n][m]<<endl;
        for(int i=1;i<=n;i++) cout<<i<<" "<<path[n][m][i]<<endl;
        return 0;
    }
    

    如果你依照上述思想写出了dp程序并提交,恭喜你,只有90分。

    #那么这是为什么呢?

    回到题面,我们会发现小小的一行字,人畜无害的样子:

    P.S.要求答案的字典序最小

    你会发现如果这样做,方案输出是错的。

    如何使字典序最小呢?这需要我们倒着枚举。

    设表示的意思为“不给”第i家公司k台机器(k的值域同上),那么状态转移方程需改为:

    f[i][j]=max(f[i][k],f[i-1][k]+graph[i][j-k]);

    再根据这个,对于path数组的更新操作进行一些微调,即可得到满分程序了:

    #include<bits/stdc++.h>
    using namespace std;
    int f[11][16],graph[11][16],path[11][16][11],n,m;
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cin>>graph[i][j];
        }
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)    
                for(int k=0;k<=j;k++)
                {
                    if (f[i][j]<f[i-1][k]+graph[i][j-k])
                    {
                        f[i][j]=f[i-1][k]+graph[i][j-k];
                        for(int h=1;h<i;h++) path[i][j][h]=path[i-1][k][h];
                        path[i][j][i]=j-k;//因为改为了“不给”第i家公司k台机器,所以必须如此调整
                    }
                }
        cout<<f[n][m]<<endl;
        for(int i=1;i<=n;i++) cout<<i<<" "<<path[n][m][i]<<endl;
        return 0;
    }
    
    • 1

    信息

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