1 条题解

  • 0
    @ 2025-8-24 21:41:05

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar xMinh
    **

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

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

    以下是正文


    S1 一开始看到这道题还是很好确定算法的,妥妥的是dfs+dp。先跑一遍完全背包,vis[i][j]表示体积为j的时候选不选i最优,可以把第一维压掉。如果vis[j-a[i]]选了i,那么vis[j]就不用再选一遍。这样可以确定出来一共选了多少种木桶,之后搜索,再跑布尔完全背包,因为已经把桶的大小排过序了,那么如果可以拼成体积为q的就直接输出结束程序就可以了。

    S2 注意两个小错误。

    第一个,在最初的那一遍完全背包中,如果f[j-a[i]]+value等于f[j],那也要把vis[j]设为1,因为这样会最优——在同样的f[j]下,如果vis[j]=1,那么f[j+a[i]]的值会少加1,从而保证最终的结果最优。

    第二个,这个真是无语,小错误害死人啊。在搜索完的那次完全背包中,我的初始化不是g[i]=big,而是g[q]=big……手一滑,三个人检查了一个小时,死活检查不出来,从网上下了数据才出来的……检查的时候一定要一个字一个字仔细看,不要因为语句简单就不看了,简单的语句也可能手滑打错。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define rint register int
    #define inv inline void
    #define big 1e9
    using namespace std;
    int p,q,a[101],f[20001],que[101],cnt;
    bool use[101],vis[20001],g[20001];
    inv dp()
    {
        for (rint i=0;i<=q;i++) g[i]=0;g[0]=1;
        for (rint i=1;i<=f[q];i++)
            for (rint j=a[que[i]];j<=q;j++)
                if (g[j-a[que[i]]]) g[j]=1;
        if (g[q])
        {
            printf("%d ",f[q]);
            for (rint i=1;i<=f[q];i++) printf("%d ",a[que[i]]);
            exit(0);
        }
    }
    inv dfs(int x,int dep)
    {
        if (dep==f[q]) 
        {
            dp();
            return;
        }
        if (f[q]-dep>p-x) return;
        for (rint i=x+1;i<=p;i++)
        {
            que[dep+1]=i;
            dfs(i,dep+1);
        }
    }
    int main()
    {
        scanf("%d%d",&q,&p);
        for (rint i=1;i<=p;i++) scanf("%d",&a[i]);
        sort(a+1,a+p+1);
        for (rint i=0;i<=q;i++) f[i]=big;f[0]=0;    
        for (rint i=1;i<=p;i++)
            for (rint j=0;j<=q;j++)
            {
                vis[j]=0;
                if (j>=a[i])
                {
                    int value=vis[j-a[i]]^1;
                    if (f[j-a[i]]+value<=f[j])
                    {
                        f[j]=f[j-a[i]]+value;
                        vis[j]=1;
                    }
                }
            }
        dfs(0,0);
    } 
    

    总结:

    1. 要思考一下第一个搜出来的是不是最优解,是的话可以直接剪掉。

    2. 一定要注意细节,等于号加不加是个问题,仔细思考。出错的时候一句一句认真检查,千万不要嫌麻烦,发愁的时间比检查的时间长多了。

    • 1

    信息

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