蓝桥杯:砝码称重【一种极简做法和dp做法】

这道题有两种做法,先介绍第一种方法,这种方法我是把每个砝码抽象成步数,即题目问你给你n个移动的机会,每个机会有一个固定的权重wi,你可以向前走wi,也可以向后走wi,也可以不走,当然起始位置为0,且位置为-x和x是等价的,即你可以走到-x那么你也可以走到x;

思路是这样的;

用一个vector<int>存储可以走到的位置,用一个记录数组记录位置x是可以被走到,如果可以即st[x]=1,否则st[x]=0;

1:考虑第i个移动的机会,其权重为wi,且前i-1个可以移动的位置都已经计算完毕

2:利用遍历vector里的所有元素,不妨设遍历到sto[j],如果abs(sto[j]+wi])没有被走过,则st[sto[j]+wi]=1,且将sto[j]+wi插入到vector中,且对abs(sto[j]+wi])、abs(wi)进行相同的操作;

3:当以上循环结束时,vector的长度就是答案;

说实话这道题有一点像走台阶,即你可以向前走x步也可以走y步,然后问你有多少种方法可以走到一个特定的位置;

那么接下来就是代码了;

#include<iostream>
#include<algorithm>
using namespace std;

const int N=100010;

vector<int> sto;
int st[N];
int n;

int main(){
    
    cin>>n;
    
    for(int i=0;i<n;i++){
        
        int x; cin>>x;
        
        int mid=sto.size();
        
        for(int j=0;j<mid;j++){
            
            int x1=abs(x-sto[j]); int y1=abs(x+sto[j]);
            if(!st[x1]&&x1!=0) st[x1]=1,sto.push_back(x1);
            if(!st[y1]&&y1!=0) st[y1]=1,sto.push_back(y1);
        }
        if(!st[x]) st[x]=1,sto.push_back(x);
        
    }

    
    cout<<sto.size();
    
}

那么接下来就是dp的方法了,这个方法我们可以用集合的角度进行思考,这道题说白了就是一个简单的背包【本菜鸟惭愧】;

首先对每一个状态进行定义,即定义集合的含义;

1:f[i][j]为选取前j个物品前重量为i的集合是否为空;

然后就是进行想状态转移的方程了,这里考虑最后一个不同点,即考虑第j个物品,这无非有三种选择;

1:不选第j个物品,即我们看f[j][i-1]是否为空即。

2:选第j个物品,

(1)即看f[abs(wi-j)][i-1]是否为空【选后走wi步】

(2)即看f[abs(wi+j)][i-1]是否为空【wi为第i个移动的步数】【向前走wi步】

那么接下来就是代码了

#include<iostream>
#include<algorithm>
using namespace std;

const int N=110000;

int f[N][110];
int n;
int st[N];

int main(){
    
    cin>>n;
    int max=0;
    
    for(int i=1;i<=n;i++) cin>>st[i],max+=st[i];
    
    for(int i=0;i<=n;i++) f[0][i]=1;
    
    for (int i = 1; i <= n; i++) {

		for (int j = 1; j <= max; j++) {

			if (f[j][i - 1]) f[j][i] = 1;//不取
			if (f[abs(j + st[i])][i - 1]) f[j][i] = 1;//取负
			if (f[abs(j - st[i])][i - 1]) f[j][i] = 1;//取正

		}

	}
    
    int ans=0;
    
    for(int i=1;i<=max;i++){
        if(f[i][n]) ans++;
    }
    cout<<ans;
    
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值