試題 算法提高 盾神與砝碼稱重
資源限制
時間限制:1.0s 內存限制:256.0MB
問題描述
有一天,他在宿舍裏無意中發現了一個天平!這個天平很奇怪,有n個完好的砝碼,但是沒有遊碼。盾神爲他的發現興奮不已!於是他準備去稱一稱自己的東西。他準備好了m種物品去稱。神奇的是,盾神一早就知道這m種物品的重量,他現在是想看看這個天平能不能稱出這些物品出來。但是盾神稍微想了1秒鐘以後就覺得這個問題太無聊了,於是就丟給了你。
輸入格式
第一行爲兩個數,n和m。
第二行爲n個數,表示這n個砝碼的重量。
第三行爲m個數,表示這m個物品的重量。
輸出格式
輸出m行,對於第i行,如果第i個物品能被稱出,輸出YES否則輸出NO。
樣例輸入
4 2
1 2 4 8
15 16
樣例輸出
YES
NO
樣例輸入
4 1
10 7 1 19
6
樣例輸出
YES
數據規模和約定
1<=n<=24, 1<=m<=10.
題解
(假設物品放在天平左端)每個砝碼只有三種狀態:放在天平右端;放在天平左端;不使用。按照這種思路 最多要算 324=28*1010 看似會超時,很多情況及時剪枝回溯,另外,把砝碼按從大到小排序也可以加快計算,是可以AC的。
剪枝:如果剩下的砝碼都放在天平右端,都比左端輕,那麼不可能稱出來。
sum[i] 存儲第 i 到第 n 個砝碼的重量和。
AC代碼如下
#include<cstdio>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
int sum[30];
int fama[30];
int wupin[20];
bool dfs(int left,int k){
if(sum[k]<abs(left)) //剩下的砝碼都放到右端天平都不能平衡
return false;
if(left==0||abs(left)==sum[k]) //天平平衡了或者剩下的砝碼都放在右端能平衡
return true;
if(k==n) //用滿了n個砝碼依然沒稱出來
return false;
if(dfs(left-fama[k],k+1)) //左物右碼
return true;
if(dfs(left+fama[k],k+1)) //左物左碼
return true;
if(dfs(left,k+1)) //不放
return true;
return false;
}
int main(){
int all=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&fama[i]);
all+=fama[i];
}
for(int j=0;j<m;j++)
scanf("%d",&wupin[j]);
sort(fama,fama+n,greater<int>());
sum[0]=all;
for(int i=1;i<n;i++){
sum[i]=sum[i-1]-fama[i-1];
}
for(int i=0;i<m;i++){
if(dfs(wupin[i],0))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
PS.這裏也放一下錯誤的解法,就是每次從剩下的砝碼挑一個,然後只要考慮兩種情況,放在天平左邊或者右邊,但是複雜度比前面的大,因爲要 全排列砝碼,每次挑一個,而且會有重複的,先挑a再挑b,和先挑b再挑a是一樣的,所以這種做法一組測試也沒跑出來。
#include<cstdio>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
bool vis[30];
int fama[30];
int wupin[20];
bool dfs(int left,int have){ //left是還需要的砝碼 have是還有的所以砝碼總重量
if(abs(have)<abs(left))
return false;
if(left==0||abs(have)==abs(left))
return true;
for(int i=0;i<n;i++)
if(!vis[i]){
vis[i]=1;
if(dfs(left-fama[i],have-fama[i])) //左物右碼
return true;
if(dfs(left+fama[i],have-fama[i])) //左物左碼
return true;
vis[i]=0;
}
return false;
}
int main(){
int all=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&fama[i]);
all+=fama[i];
}
for(int j=0;j<m;j++)
scanf("%d",&wupin[j]);
sort(fama,fama+n,greater<int>());
for(int i=0;i<m;i++){
memset(vis,0,sizeof(vis));
if(dfs(wupin[i],all))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}