洛谷 P1441 【砝码称重】题解

做这道题之前建议先看一下洛谷P2347这一道题,总体思路与这一道题十分相似(这一道题主要是多了一个DFS的过程),下面来说一下这道题(敲黑板):

使用的算法:DFS+DP(看到数据范围这么小应该首先想到的就应该是DFS)

做法:首先通过DFS枚举不取哪M个砝码的情况,再把每种情况依次DP,用一个ma记录最大值(详情见代码部分)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,a[21],f[2001],b[21],last=0,num=0,ma=0;
void search(int k)
{
    if(k==m+1)//当取出了M个砝码时开始计算
    {
        memset(f,0,sizeof(f));//清零!!!这一步不能忘掉
        f[0]=1;//当重量为0时要记为有一种情况,不然结果永远是0
        for(int i=1;i<=n;i++)
        {
            if(b[i]==0)//如果这个砝码没有被拿走
            {
                for(int j=2000;j>=0;j--)//必须倒叙!不然可能f[4]用了4g的砝码,f[8]的时候又把4g的砝码拿出来用一遍
                {
                    if(j+a[i]<=2000&&f[j]!=0)//如果这个重量可以取到且加上新砝码后重量小于等于最大重量(max_n*max_a[I]=2000)
                    {
                        f[j+a[i]]=1;//标记加上砝码后的重量也可以取到
                    }
                }
            }
        }
        num=0;
        for(int i=1;i<=2000;i++)//看哪些重量可以取到
            if(f[i])
                num++;
        if(num>ma)//记录最大值
            ma=num;
        return;
    }
    for(int i=last+1;i<=n;i++)//枚举取砝码的情况(这里采用的是顺次枚举,减少耗时)
    {
        b[i]=1;//记录为取过了
        last=i;//记录取到哪一个了
        search(k+1);//接着往下取
        b[i]=0;//回溯
    }
}
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];//读入
    search(1);//枚举每种情况
    cout<<ma;
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注