题目描述:
有一堆石子,一个无游标的天平,已知石子的重量,石子可以放天平的任意一边,问能否用石子称出某个询问的重量。

思路:
首先可以发现石子最多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;
}