JAG Contest 2016 DomesticB E ぼくのかんがえたさいきょうのおふとん

最適なおふとんの並べ方が分かっていたとすると,おふとんを一番上から連続して使うことしか出来ないので,$M$日間のぬくもり需要$d_j$の順番は関係なくなる.sort後は$d_i < d_{i+1}$となっていて,$d_{i+1}$の最小は$d_i$で最小であったおふとんの並び方に新しくおふとんを追加するかしないか,となる.

$$ dp[i][j] := i日目まででおふとん集合jの時の最小値 $$

として,動的計画法.集合$j$の部分集合のminと考えるのではなく,集合$j$に要素を一個加えたものを更新する.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <bitset>

#define REP(i, k, n) for(int i = k; i < n; i++)
#define rep(i, n) for(int i = 0; i < n; i++)
#define INF 1<<30

using namespace std;
typedef long long ll;

ll dp[105][1<<15];
ll res[1<<15];

int main() {
  int n, m;
  while(cin >> n >> m) {
      if(n == 0 && m == 0) break;

      vector<ll> s(n), d(m);
      rep(i, n) cin >> s[i];
      rep(i, m) cin >> d[i];

      sort(d.begin(), d.end());

      rep(i, 105) rep(j, 1<<15) dp[i][j] = INF;
      rep(j, 1<<15) dp[0][j] = 0;

      rep(i, m) {
          ll val = INF;
          rep(j, 1<<n) {
              ll sum = 0;
              rep(k, n) {
                  if(j & (1<<k)) {
                      sum += s[k];
                  }
              }

              rep(k, n) {
                  if(j & (1<<k)) continue;
                  dp[i][j | (1<<k)] = min(dp[i][j | (1<<k)], dp[i][j]);
              }

              dp[i+1][j] = min(dp[i+1][j], dp[i][j] + abs(d[i] - sum));
          }
      }

      ll ans = INF;
      rep(j, 1<<n) {
          ans = min(ans, dp[m][j]);
      }

      cout << ans << endl;
  }
  return 0;
}
Jun 17th, 2016