解法.全探索
番目の薬品に対して釣り合うような分銅の置き方が存在するとき,各 に対してある が存在して を満たす.このとき, が -1 のとき 番目の分銅は薬品と同じ側に置かれ, 0 のとき使用しなく,1 のとき薬品と反対の側に置くことを表している.したがって右辺の値の集合 を 時間で全列挙して,各薬品の重さ に対して かどうかを判定すればよい.
次に,与えられた分銅ではすべての薬品に対して釣り合うような置き方が存在しない場合を考える.ここで, 番目の薬品が釣り合うような分銅の置き方がないとする.すなわち, である. 番目の薬品が釣り合うように追加する分銅の重さの候補の集合は である. の各重りについて追加してすべての薬品を釣り合わせることができるかを判定すれば答えが求まる.
計算時間:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void enumerateWeight(const int idx, ll sum,
unordered_set<ll> &comb, const vector<int> &w) {
if (idx < 0) {
comb.insert(sum);
return ;
}
for (ll select = -1; select <= 1; ++select)
enumerateWeight(idx - 1, sum + select * w[idx], comb, w);
}
int solve(const int n, const int m) {
vector<int> a(n), w(m);
for (auto &a_i : a) cin >> a_i;
for (auto &w_i : w) cin >> w_i;
unordered_set<ll> comb;
enumerateWeight(m - 1, 0, comb, w);
bool can_measure = all_of(a.begin(), a.end(), [&comb](int a_i) { return comb.count(a_i); });
if (can_measure) return 0;
ll min_add_w = LLONG_MAX, idx = 0;
while (idx < n && comb.count(a[idx])) ++idx;
for (ll sum : comb) {
ll add_w = abs(sum - a[idx]);
can_measure = all_of(a.begin(), a.end(), [&comb, &add_w](int a_i) {
return comb.count(a_i) || comb.count(a_i - add_w) || comb.count(a_i + add_w);
});
if (can_measure) min_add_w = min(min_add_w, add_w);
}
return min_add_w < LLONG_MAX ? min_add_w : -1;
}
int main() {
cin.tie(0); ios::sync_with_stdio(false);
int n, m;
while (cin >> n >> m, n) cout << solve(n, m) << '\n';
return 0;
}
C++ の STL を復習したので all_of
とか使いたくなったけど横に長くなるのどうすれば良いんだろう.どこで改行すればキレイに見れるのかまったく分からない.