superoj732 砝码称重

这篇博客讨论了一种使用分治策略解决砝码称重问题的方法。问题描述涉及n个砝码和m个物品的重量,要求判断每个物品能否被称出。通过将砝码分为两组,分别进行3的幂次方种组合并存储在哈希表中,然后检查另一半的组合是否存在匹配项,从而达到高效求解的目的。时间复杂度为O(2*3^(n/2))。

题目描述

输入格式

第一行为两个数,n 和 m 。
第二行为 n 个数,表示这 n 个砝码的重量。
第三行为 m 个数,表示这 m 个物品的重量。

输出格式

输出 m 行,对于第 i 行,如果第 i 个物品能被称出,输出 “YES” 否则输出“NO”。

样例数据 1

输入  [复制]

4 2 
1 2 4 8 
15 16

输出

YES 
NO

备注

【数据范围】
30% 数据,n<=10;
50% 数据为随机数据;
100% 数据保证:1<=n<=24, 1<=m<=10。所有重量的绝对值在 1014 以内。

分析: 暴力搜索(3^n)

分治 每个砝码可以放左放右不放 把24个砝码分成俩份

一半求出3^12种可能情况,存在hash中

另一半求出3^12种可能,到hash中找有没有匹配的另一半

时间复杂度O(2* 3^(n/2))

代码

#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>

using namespace std;
//map <long long,bool> q;
long long n,m;
long long fama[50];
long long thing[50];
long long size;
long long p[1000000];
long long hash[2000000];
long long read()
{
	long long  k=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
	while(c>='0'&&c<='9') {k=k*10+c-'0'; c=getchar();}
	return k*f;
}

long long gethash(long long x)
{
	long long u=((x%1000007)+1000007)%1000007;
    while(hash[u]&&hash[u]!=x) u++;
//    hash[u]=x;
    return u;
}

int main()
{
//	freopen("lx.in","r",stdin);
//	freopen("lx.out","w",stdout);
	long long i,j,k;
	n=read();
	m=read();
	for(i=1;i<=n;i++)
	  {
	  	fama[i]=read();
	  }
	for(i=1;i<=m;i++)
	  {
	  	thing[i]=read();
	  }
	
	p[1]=0;
	size=1;
	for(i=1;i<=n/2;i++)
	  {
	  	long long dd=size;
	  	  for(j=1;j<=dd;j++)
	  	    {
	  	       p[++size]=p[j]+fama[i];
	  	       p[++size]=p[j]-fama[i];
			}
	  }
    for(i=1;i<=size;i++)
      {
	  hash[gethash(p[i])]=p[i];
      }
	p[1]=0;
	size=1;
	for(i=n/2+1;i<=n;i++)
	  {
	  	long long dd=size;
	  	  for(j=1;j<=dd;j++)
	  	    {
	  	       p[++size]=p[j]+fama[i];
	  	       p[++size]=p[j]-fama[i];
			}
	  }
	for(j=1;j<=m;j++)  
	{
	bool oo=0;
	for(i=1;i<=size;i++)
	  if(hash[gethash(thing[j]-p[i])]==thing[j]-p[i])
       {oo=1;break;}
	if(oo) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;       	
    }
	
	return 0;
} 


蓝桥杯砝码称重问题是经典的算法题目之一,通常出现在竞赛训练题库中。这个问题的核心在于通过给定的一组砝码重量以及天平的操作规则,求解能够称出的最大重量范围或者特定条件下能称出的所有可能的重量。 ### 题目背景 假设有一个天平和一组砝码,并给出每种砝码的数量及对应的重量值(例如有3个1克的砝码、2个5克的砝码等)。目标是计算这组砝码可以组合出的不同重量总数是多少,或者是最大可称量多少。 --- #### **解法思路** 为了更好地解决这类问题,我们需要明确以下几个关键点: 1. **状态表示** 使用动态规划的思想,将每个物品看作一种选择机会。设`dp[i]` 表示是否可以通过当前选取某些砝码得到重量i 。初始化时只有 `dp[0]=true` 因为我们默认存在零重量情况即什么都不放的状态。 2. **遍历顺序** 对于每一个类型的砝码k (其单件质量为w[k]) ,从最小到大枚举所有可能放置数量n_k , 更新新的可达权重集合。 3. **转移方程** 假如现在处理第j 种砝码并且该种最多可用num[j] 次,则对于之前已经标记过的可行总重量x : - 如果 x + w * i ≤ MAX_WEIGHT 则尝试设置 dp[x+w*i ] = true 4. 最终统计有多少个位置上dp数组元素变为真即可获得答案——也就是总的不重复的有效整数重量数目。 --- #### 示例程序(Python) ```python def max_weight(weighs, nums): # 初始化DP表,默认只能达到0kg limit = sum([a*b for a,b in zip(weighs,nums)])+1 dp = [False]*limit dp[0] = True for idx,wgt in enumerate(weighs): temp_dp=[d for d in dp] count=nums[idx]+1 current_sum=wgt while(current_sum<limit and count>0): if(temp_dp[current_sum-wgt]==True): dp[current_sum]=True current_sum+=wgt; count-=1; return len([v for v in dp if v]) # 测试数据输入部分开始 if __name__ == "__main__": weights=input().strip().split(',') numbers=input().strip().split(',') int_weights=list(map(int,weights)) int_numbers=list(map(int,numbers)) print(max_weight(int_weights,int_numbers)) ``` 上述伪代码片段展示了如何利用布尔型列表模拟所有的可能性并最终得出结果计数值过程的一个简化版本示意而已实际比赛中需要考虑边界条件更细致些! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值