其他分享
首页 > 其他分享> > 洛谷P1441 砝码称重

洛谷P1441 砝码称重

作者:互联网

给定n砝码,要求删掉m砝码,问怎么删,剩下的砝码保留的最多。

考虑原来的砝码一共可以称出多少种重量,再用dfs深搜,每次深搜删去那个重量,搜完后求出剩余的重量。

如果是1 2 2,则1,1+2,1+2+2||||2,1+2,1+2+2||||2,1+2,1+2+2 共9个数字,每次搜索的时候删去其所影响的总方案

另搜索1,则删去1,1+2,1+2+2

搜索2,则删去2,1+2,1+2+2。

但是如果样例中的m=1改为2.

则要删去1相关的数后再删去2相关的数字,1,1+2,1+2+2,2,1+2,1+2+2。

很遗憾,这种算法是错误的。QAQ

 

dfs仍然是倒着搜,但是搜完后对搜完的整体进行dp(01背包)。

设计一个flag储存在dfs过程中哪个被排除了。dfs完后调用dp:

DP:

除dp[0]=1,其他全部设为0,如果某个重量可以被砝码组合,那么这个重量-这个砝码的重量一定可以被组合。所以有了动态转移方程。

如果(flag[i]可用的话)

if (dp[j-weight[i]]==1) (j指当前搜到的重量,weight是这个砝码的质量) dp[j]=1;

最后找一下weight数组里有多少个。

#include <iostream>
using namespace std;
int a[21],weight[2001],m,n,b[21],sum,ans,cnt;

void dp()
{
    for (int i=1;i<=sum;i++) weight[i]=0; weight[0]=1; cnt=0; //initialize
    for (int i=1;i<=n;i++)
    {
        if (a[i]==0)
        for (int j=sum;j>=b[i];j--)
            if (weight[j-b[i]]!=0) weight[j]=1;
    }
    for (int i=1;i<=sum;i++)
        if (weight[i]) cnt++;
    if (cnt>ans) ans=cnt;
    return;
}

void dfs(int depth,int initial)
{
    if (depth==m) {dp(); return;}
    else
    {
        for (int i=initial;i<=n;i++){
            a[i]=1;
            dfs(depth+1,i+1);
            a[i]=0;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    cin>>n>>m;
    for (int i=1;i<=n;i++) {cin>>b[i]; sum+=b[i];} //记录了sum,这样dp时循环就方便一点了。
    dfs(0,1);
    cout<<ans;
}

  

标签:洛谷,weight,P1441,int,dfs,砝码,删去,dp,称重
来源: https://www.cnblogs.com/asanagiyantia/p/12109134.html