题目描述:
有一堆石子,一个无游标的天平,已知石子的重量,石子可以放天平的任意一边,问能否用石子称出某个询问的重量。
思路:
首先可以发现石子最多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; }