• Luogu P1441 砝码称重(fj省选)


     P1441 砝码称重

    题目描述

    现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。

    输入输出格式

    输入格式:

    输入文件weight.in的第1行为有两个整数n和m,用空格分隔

    第2行有n个正整数a1,a2,a3,……,an,表示每个砝码的重量。

    输出格式:

    输出文件weight.out仅包括1个整数,为最多能称量出的重量。

    输入输出样例

    输入样例#1:
    3 1
    1 2 2
    输出样例#1:
    3

    说明

    【样例说明】

    在去掉一个重量为2的砝码后,能称量出1,2,3共3种重量。

    【数据规模】

    对于20%的数据,m=0;

    对于50%的数据,m≤1;

    对于50%的数据,n≤10;

    对于100%的数据,n≤20,m≤4,m<n,ai≤100。

      这是福建省历届夏令营的题。。洛谷难度标签为提高+/省选-。。。

      这道题刚看没有思路,但只要跟你讲这是dfs+dp就会有思路了。。

      没错,这道题用dfs+dp。

      dfs 用来搜索每一种舍弃m个砝码后, 还有什么砝码是剩下的。

      dp用来求每一种舍弃m个砝码后,能量出种多少重量。

      dp[j]表示重量为j时,能否量出j。最后答案dp[j]里有多少个true

      相信大家已经心里有点底子了,看代码吧。

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 int f[2005], ans, a[25];
     5 int m, n, tf[25];
     6 
     7 int Max(int _a, int _b)
     8 {
     9     return ((_a > _b) ? _a : _b);
    10 }
    11 
    12 void dp()
    13 {
    14     int ret, tot;    //ret是表示这种舍弃的情况 能量出多少不同的重量
    15     memset(f, 0, sizeof(f));    //要记得每次重置。。。
    16     ret = tot = 0;
    17     f[0] = 1;
    18     for(int i=1; i<=n; i++)
    19     {
    20         if(tf[i]) continue;        //如果这个砝码被舍弃了 就不考虑
    21         for(int j=tot; j>=0; j--)
    22         {
    23             if(f[j] && !f[j+a[i]])    //能量出j的重量 且j+a[i]的重量未被量(防止ret重复自增)
    24             {
    25                 f[j+a[i]] = 1;
    26                 ret++;
    27             }
    28         }
    29         tot += a[i];    //表示前i个(不包括i)砝码能量出的最大重量 
    30                         //这样每次就可以直接从背包能表示的最大重量开始算 速度会快很多
    31                         //(跟题解dalao学的)
    32     }
    33     ans = Max(ans, ret);    //更新最大值
    34 }
    35 
    36 void dfs(int dep, int now)    //dep是当前在考虑第dep个砝码 now为已经舍去的砝码数
    37 {
    38     if(now > m) return;        //如果舍弃的砝码大于m
    39     if(dep > n+1) return;    //如果考虑的砝码超过n。。
    40     if(dep == n+1)        //如果考虑完了所有砝码
    41     {
    42         if(now < m) return;    //如果舍弃的砝码小于m
    43         if(now == m)        //考虑完所有砝码 且舍去了m个砝码 则dp()
    44             dp();
    45     }
    46     dfs(dep+1, now);
    47     tf[dep] = 1;    
    48     dfs(dep+1, now+1);
    49     tf[dep] = 0;        //记得状态要调回来
    50 }
    51 
    52 int main()
    53 {
    54     scanf("%d%d", &n, &m);
    55     for(int i=1; i<=n; i++)
    56         scanf("%d", &a[i]);
    57     dfs(1,0);
    58     printf("%d", ans);
    59     return 0;
    60 }
  • 相关阅读:
    关于Android架构那些事
    关于投资那些事
    关于单例模式的N种实现方式
    关于如何避免Android中Bitmap引起的OutOfMemoryError
    关于Java设计模式的一些概况
    阿里云服务器使用记录:服务器运行的网页无法访问
    毕业设计进度:3月22日
    前端框架:bootstrap多个模态框跳转使用时发生的页面左移问题
    毕业设计进度:3月20日
    毕业设计进度:3月19日
  • 原文地址:https://www.cnblogs.com/yBaka/p/7747728.html
Copyright © 2020-2023  润新知