砝码称重

10 篇文章 0 订阅

题目网址:https://www.dotcpp.com/oj/problem1548.html

题目描述

 有一天,他在宿舍里无意中发现了一个天平!这  个天平很奇怪,有n个完好的砝码,但是没有游码。盾神为他的发现兴奋不已!于是他准备去称一称自己的东西。他准备好了m种物品去称。神奇的是,盾神一早就  知道这m种物品的重量,他现在是想看看这个天平能不能称出这些物品出来。但是盾神稍微想了1秒钟以后就觉得这个问题太无聊了,于是就丢给了你。

输入

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

第三行为m个数,表示这m个物品的重量。 

数据规模和约定
1< =n< =24,  1< =m< =10.

输出

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

样例输入 

4 2
1 2 4 8
15 16

样例输出

YES
NO

注:题目中没有说明,天平两侧砝码都可以放

 思路一:对于砝码有放在左侧,放在右侧或不放三种选择。而且,此题数据量不大,可以dfs求解出所有的可能性。

代码如下:

#include <iostream>//砝码可以放在天平的任意一侧 
#include <cstdio>//dfs
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#define cla(a, sum) memset(a, sum, sizeof(a))
#define rap(i, m, n) for(int i=m; i<=n; i++)
#define rep(i, m, n) for(int i=m; i>=n; i--)
#define bug printf("???\n")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<ll, ll> Pl;
const int Inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int mod=998244353;
const int maxn = 1e6+5;
const int N=1e5;
template <typename T> void read(T &x){
    x = 0; int f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}
//dp为标记数组,记录所有可能性
int n,m,sum=0;
int dp[maxn]={0},a[55],b[55];
int ok[55];

void dfs(int x,int y,int pos){
	if(pos>n+1)return ;
    int c=abs(x-y);
	dp[c]=1;
	dfs(x,y,pos+1);
	dfs(x+a[pos],y,pos+1);
	dfs(x,y+a[pos],pos+1);	
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
	}
	for(int i=1;i<=m;i++)
	    cin>>b[i];
	dfs(0,0,1);
	for(int i=1;i<=m;i++){
		if(b[i]>sum||dp[b[i]]==0)printf("NO\n");
		else printf("YES\n");
	}
	
	return 0;
}

 

思路二:一般来说,如果数据量较大,dfs会超时。此类题目也可以转化为动态规划问题

用dp[i][j]来表示前i个砝码,是否可以称出j,然后要不加ai,要不减ai,要不不加也不减 。(1表示可以,0表示不可以)

代码如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#define cla(a, sum) memset(a, sum, sizeof(a))
#define rap(i, m, n) for(int i=m; i<=n; i++)
#define rep(i, m, n) for(int i=m; i>=n; i--)
#define bug printf("???\n")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<ll, ll> Pl;
const int Inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int mod=998244353;
const int maxn = 1e6+5;
const int N=1e5;
template <typename T> void read(T &x){
    x = 0; int f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}

int n,m,a[55];
int V=0,dp[35][500005];
int ok[500005],c;
//用dp[i][j]来表示前i个砝码,是否可以称出j,然后要不加ai
//要不减ai,要不不加也不减 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		V+=a[i];
	}
	dp[0][V]=1;
	//防止出现负数,扩大V, -V~V 变为 0~2*V 
	//dp[0][V]相当于dp[0][0] 
	for(int i=1;i<=n;i++){
		for(int j=0;j<=V*2;j++){
			if(dp[i-1][j]){
				dp[i][j]=1;
				if(j+a[i]<=V*2)
					dp[i][j+a[i]]=1;
				if(j-a[i]>=0)
					dp[i][j-a[i]]=1;
			}
		}
	}
	for(int i=V+1;i<=2*V;i++)
		if(dp[n][i])
			ok[i-V]=1;
	for(int i=1;i<=m;i++){
		scanf("%d",&c);
		if(c>V)
			printf("NO\n");
		else if(ok[c])
			printf("YES\n");
		else 
			printf("NO\n");
	}

	return 0;
}
/*
2 2
1 3
2 4
*/

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值