蓝桥杯 盾神与砝码称重 dfs 剪枝

问题描述
  有一天,他在宿舍里无意中发现了一个天平!这个天平很奇怪,有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.
每个砝码有三种情况。
1:不使用这个砝码。
2:将这个砝码和物品放在同一侧。
3:将这个砝码放在物品另一侧。
这道题目不优化剪枝会超时。
可以先自己试着写一个朴素代码,然后再看如何优化更容易理解。
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n, m;
 4 int fm[30]; //fm[i]表示第i个砝码的重量
 5 int sum[30]; //sum[i]表示前i个砝码重量和
 6 bool flag;
 7 void dfs(int x, int len) { //x:当前要测量的物品重量,len:当前可用前len个砝码去称
 8     //如果还有可用砝码并且没称出当前重量并且备选砝码重量和大于等于当前要测的重量
 9     if (len >= 1 && flag == false && abs(x) <= sum[len]) {
10         if (abs(x) == fm[len]) {
11             flag = true;
12         } else {
13             //递归的顺序对运行时间有影响
14             dfs(x - fm[len], len - 1); //把fm[len]这个砝码放在物品的另一侧
15             dfs(x, len - 1); //不使用fm[len]这个砝码
16             dfs(x + fm[len], len - 1); //把fm[len]这个砝码放在物品同侧
17         }
18     }
19 }
20 int main() {
21     cin >> n >> m;
22     for (int i = 1; i <= n; i++) {
23         cin >> fm[i];
24     }
25     sort(fm + 1, fm + 1 + n); //对砝码重量排序
26     sum[0] = 0; //计算前n个砝码总和
27     for (int i = 1; i <= n; i++) {
28         sum[i] = sum[i - 1] + fm[i];
29     }
30     while (m--) {
31         flag = false;
32         int x;
33         cin >> x;
34         dfs(x, n); //开始搜索。现在要测量的物品重量为x,现在可用的砝码个数是n个
35         if (flag) {
36             cout << "YES" << endl;
37         } else {
38             cout << "NO" << endl;
39         }
40     }
41     return 0;
42 }

 2020年10月22日更新:感谢评论区大佬@ qdu_yyh的指正

现在14行和16行的注释已更正

原文地址:https://www.cnblogs.com/fx1998/p/12734817.html