http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3998
组队训练时候的一道题。题意是用给出的6个数利用加减乘除求出一个最接近给定数字的数,输出解决方案。
直接用状态压缩的方法,利用集合并,在两集合得出的数值之间加入运算符,存到新的集合之中去。如果不加入剪枝,总的状态数多达50W个,STL的常数大,所以会直接超时了。然后我们可以加上这样的一个剪枝,对于同一个状态,插入的数不应该重复,因为这样的一个数我们只需要一种获取方式就够了。于是,我们就可以用set来判断是否有数值是重复出现的。这样子的剪枝,就减去了大部分的状态了,最终只剩下大约3W种状态左右,然后就能顺利通过所有数据了。
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <set> 7 8 using namespace std; 9 10 typedef long long LL; 11 const char *OP = "+-*/"; 12 const int N = (1 << 6) + 10; 13 struct Node { 14 LL sum ,v1, v2; 15 int s1, s2, op; 16 Node() {} 17 Node(LL _sum, int _s1, int _s2, LL _v1, LL _v2, int _op) { 18 sum = _sum; 19 s1 = _s1; 20 s2 = _s2; 21 v1 = _v1; 22 v2 = _v2; 23 op = _op; 24 } 25 } ; 26 vector<Node> res[N]; 27 28 void PRE() { 29 LL x; 30 for (int i = 0; i < N; i++) res[i].clear(); 31 Node tmp; 32 for (int i = 0; i < 6; i++) { 33 cin >> x; 34 tmp = Node(x, 0, 0, 0ll, 0ll, -1); 35 res[1 << i].push_back(tmp); 36 } 37 } 38 39 void work() { 40 int end = 1 << 6; 41 // int sum = 0; 42 Node tmp; 43 set<int> has; 44 for (int i = 0; i < end; i++) { 45 has.clear(); 46 for (int t = i & (i - 1); t > 0; t = i & (t - 1)) { 47 int op = i ^ t, szt = res[t].size(), szop = res[op].size(); 48 for (int ii = 0; ii < szt; ii++) { 49 for (int jj = 0; jj < szop; jj++) { 50 tmp = Node(res[t][ii].sum + res[op][jj].sum, t, op, res[t][ii].sum, res[op][jj].sum, 0); 51 if (tmp.sum > 0 && has.find(tmp.sum) == has.end()) res[i].push_back(tmp), has.insert(tmp.sum); 52 tmp = Node(res[t][ii].sum - res[op][jj].sum, t, op, res[t][ii].sum, res[op][jj].sum, 1); 53 if (tmp.sum > 0 && has.find(tmp.sum) == has.end()) res[i].push_back(tmp), has.insert(tmp.sum); 54 tmp = Node(res[t][ii].sum * res[op][jj].sum, t, op, res[t][ii].sum, res[op][jj].sum, 2); 55 if (tmp.sum > 0 && has.find(tmp.sum) == has.end()) res[i].push_back(tmp), has.insert(tmp.sum); 56 if ((res[op][jj].sum != 0) && (res[t][ii].sum % res[op][jj].sum == 0)) { 57 tmp = Node(res[t][ii].sum / res[op][jj].sum, t, op, res[t][ii].sum, res[op][jj].sum, 3); 58 if (tmp.sum > 0 && has.find(tmp.sum) == has.end()) res[i].push_back(tmp), has.insert(tmp.sum); 59 } 60 } 61 } 62 } 63 // sum += res[i].size(); 64 } 65 // cout << sum << endl; 66 } 67 68 void dfs(int id, LL val) { 69 int szid = res[id].size(); 70 for (int i = 0; i < szid; i++) { 71 if (res[id][i].sum == val) { 72 if (res[id][i].op == -1) return ; 73 dfs(res[id][i].s1, res[id][i].v1); 74 dfs(res[id][i].s2, res[id][i].v2); 75 cout << res[id][i].v1 << ' ' << OP[res[id][i].op] << ' ' << res[id][i].v2 << " = " << val << endl; 76 return ; 77 } 78 } 79 } 80 81 void print(int tar) { 82 cout << "Target: " << tar << endl; 83 LL mn = 0x7777777777777777ll; 84 int end = 1 << 6, mk; 85 for (int i = 0; i < end; i++) { 86 int szi = res[i].size(); 87 for (int j = 0; j < szi; j++) { 88 if (abs(mn - tar) > abs(res[i][j].sum - tar)) { 89 mn = res[i][j].sum; 90 mk = i; 91 } 92 // if (i == end - 1) { 93 // cout << res[i][j].sum << endl; 94 // } 95 // if (res[i][j].sum == 400) { 96 // for (int j = 0; j < 6; j++) { 97 // putchar((i & (1 << j)) != 0 ? '1' : '0'); 98 // } 99 // cout << "Ahhhhhh~" << endl; 100 // dfs(i, res[i][j].sum); 101 // } 102 } 103 } 104 // for (int i = 5; i >= 0; i--) { 105 // putchar(mk & (1 << i) ? '1' : '0'); 106 // } 107 // cout << endl; 108 dfs(mk, mn); 109 cout << "Best approx: " << mn << endl << endl; 110 } 111 112 int main() { 113 // freopen("in", "r", stdin); 114 int T, tar; 115 cin >> T; 116 while (T--) { 117 PRE(); 118 cin >> tar; 119 work(); 120 print(tar); 121 } 122 return 0; 123 }
——written by Lyon