首页 > 其他分享 >3417. 砝码称重

3417. 砝码称重

时间:2022-11-07 23:33:37浏览次数:56  
标签:int sum dfs 3417 step 砝码 include 称重

https://www.acwing.com/problem/content/3420/

一眼dp,但是还是先走个暴搜看看,开始的时候我这样想,由于天平两边都可以称,需要减的操作,数组无法存储负数下标,于是我这里加了个偏移量100000,于是只过了一半的数据233(但是实际上小于0的下标不需要计算,因为砝码嘛,也需要联系实际,小于0的重量物品怎么可能称嘛!)

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
const int M = 1e5+1000;
int a[N];
int n;
int st[M];
int cnt;
void dfs(int step,int sum)
{
    if(step==n+1)
    {
        st[sum+100000]++;
        return;
    }
    dfs(step+1,sum);
    dfs(step+1,sum+a[step]);
    dfs(step+1,sum-a[step]);
}
int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(0,0);
    for(int i=100001;i<M;i++)if(st[i])cnt++;
    cout << cnt << endl;
    
    return 0;
}

这样想过后,稍作修改,可以优化成这样:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
const int M = 1e5+10;
int a[N];
int n,cnt;
bool st[M];
void dfs(int step,int sum)
{
    if(step==n+1)
    {
        if(sum>0 && !st[sum])
        {
            cnt++;
            st[sum]=true;
        }
        return;
    }
    dfs(step+1,sum);
    dfs(step+1,sum+a[step]);
    dfs(step+1,sum-a[step]);
}
int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(0,0);
    cout << cnt << endl;
    return 0;
}

 但是怎么改变不了超时的命运,所以再进一步优化成记搜

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
const int M = 200010;
int a[N];
int n,cnt;
bool st[N][M];
bool f[M];
void dfs(int step,int sum)
{
    if(st[step][sum])return;
    st[step][sum]=1;
    f[sum]=1;//标记答案
    if(step==n+1)return;
    dfs(step+1,sum);
    dfs(step+1,sum+a[step]);
    dfs(step+1,sum-a[step]);
}
int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(0,0);
    for(int i=1;i<=M;i++)if(f[i])cnt++;
    cout << cnt << endl;
    return 0;
}

如此可以过了,但本题实际上考察的是dp233
再次尝试dp做法
首先,对于整个DP,状态表示:用f[i][j]表示,(i,j)表示从前i个砝码中选,且总重量为j的所有方案的集合,其属性(即f[i][j]本身的值)是是否为空(即j是否可以被已经选的砝码所表示),为布尔值
状态计算:对于最后一步操作:我们可以分成三份(大问题分解为小问题):1.不选最后一个砝码 2.选最后一个砝码,且放在正的方向上 3.选最后一个砝码,将其放在负的方向上
对于第一步操作:我们可以用f[i-1][j]来表示这步操作
对于第二步操作: 由于1~(i-1)之间的砝码我们未确定,但是第i个砝码(最后一个)我们是确定要选的,且放在正的方向上,也就是说,加上这最后一个砝码可以称取的重量大小为j ,用可解得子问题推出大问题,我们可以用f[i-1][j-w[i]]来表示这步操作
对于第三步操作:同第二步一样,由于1~(i-1)之前未确定,但是最后一个确定了,可以用f[i-1][j+w[i]]来表示这步操作

那么只要这三种子问题,有一种非空,即可以被表示出来,那么f[i][j]就可以被表示出来,就非空

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110,M = 200010;
int a[N];
bool f[N][M];
int n,cnt,sum;
int main()
{
    cin >> n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    f[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=sum;j++)
        {
            f[i][j]=f[i-1][j]|f[i-1][abs(j-a[i])]|f[i-1][j+a[i]];//镜像操作
        }
    for(int j=1;j<=sum;j++)
    {
        if(f[n][j])cnt++;
    }
    cout << cnt << endl;
    return 0;
}

 

标签:int,sum,dfs,3417,step,砝码,include,称重
From: https://www.cnblogs.com/lxl-233/p/16853604.html

相关文章

  • 【原子样式实践】第11篇 基于分类的原子样式名称重构
    刚接触到原子样式时,absolute/top-10/m-10/mx-10/text-primary/text-red-100都会让我们觉得语义简单,使用方便。但从样式治理的角度来说,这类命名在组件或者即时编......
  • 拍照和称重
    听闻一位可学家拿到爱因斯坦的大脑,可是他不会处理,他能做的全部事情就是称重和拍照。不会做的事情,我们能做的就很有限,横向拓展,纵向推进自我的边界,才能对世界有更深刻的理解,......
  • 称重系统设计
    1.传感器简介称重系统在工业级日常生活中应用非常广泛,从小型的电子称到大型的地磅。其中传感器大部分为电阻应变式压力传感器。一般由四个电阻应变片组成惠更斯电桥,安装在弹......
  • 织带称重MES(织带称重条码系统)怎么选?
    MES,尤其是需要跟硬件设备对接的MES,最好选用原生开发且可以灵活定制手机版本的系统,如果有心做得好一点最好采用工业互联网的思路来做,这样织带称重部分可以是一个简单的工业A......
  • 编程基础(1)- 问题 (一) | 12 个小球称重找出其中 1 个坏球
     1.问题   有12个外观完全一样的小球,其中有1个求的重量和其它11个球不一样(或称为坏球),但是不知道是轻还是重。现在你有一架天平,只能称3次。你怎么找出这1......