题目描述:
有一堆石子,一个无游标的天平,已知石子的重量,石子可以放天平的任意一边,问能否用石子称出某个询问的重量。
思路:
首先可以发现石子最多100个,每个最重100,因此最大的能称出来的重量为10000。
如果输入的询问重量超过10000,可以直接输出NO。
显然会往01背包方向考虑。由于石子可以放天平两边进行减法,我们可以将石子再复制一份负数重量的。然后做01背包。
那么一共有2*n颗石子,问他们组合可以有哪些重量。这是一个01背包。重量最大为10000。
这里注意负数石子的处理,用一维滚动的01背包是不行的,因为负数的时候会导致逆序记录的背包出问题。不过可以用二维的。
如果一定要用一维的,显然正数石子不影响,我们可以倒序背包。负数石子怎么办呢?可以正序背包。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[201],dp[10003];
int main()
{
while(cin>>n){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)cin>>a[i],a[i+n]=-a[i];
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=10000;j>=0;j--){
if(j>=a[i])
dp[j]|=dp[j-a[i]];
}
}
for(int i=n+1;i<=2*n;i++){
for(int j=0;j<=10000;j++){
if(j-a[i]<=10000)
dp[j]|=dp[j-a[i]];
}
}
int q;
cin>>q;
while(q--){
int x;
cin>>x;
if(x>10000)cout<<"NO"<<endl;
else{
if(dp[x])cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
}
return 0;
}
京公网安备 11010502036488号