AOJ0550 お菓子の分割
問題ページ
お菓子の分割 | Aizu Online Judge
解法
いかにもDPの雰囲気があるのでDPを考える。AくんとBくんでお菓子を分け合うとして dp[k][i][j] = (k番目まででAくんがi個取って最後に取ったのがAくんならj=0、Bくんならj=1) とおいてDPをする。遷移に必要なのはk-1のときのDPの値だけなので配列は2つ分持っておけば十分。
//#define __USE_MINGW_ANSI_STDIO 0 #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef vector<int> VI; typedef vector<VI> VVI; typedef vector<ll> VL; typedef vector<VL> VVL; typedef pair<int, int> PII; #define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i) #define REP(i, n) FOR(i, 0, n) #define ALL(x) x.begin(), x.end() #define IN(a, b, x) (a<=x&&x<b) #define MP make_pair #define PB push_back const int INF = (1LL<<30); const ll LLINF = (1LL<<60); const double PI = 3.14159265359; const double EPS = 1e-12; const int MOD = 1000000007; //#define int ll template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); } template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); } int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; int t[10010], dp[2][10010][2]; signed main(void) { int n; cin >> n; REP(i, n-1) cin >> t[i]; memset(dp, 0x3f, sizeof(dp)); dp[0][1][0] = dp[0][0][1] = t[0]; // k=0ならA、k=1ならB int cur = 0, nxt = 1; FOR(i, 1, n) { REP(j, n) REP(k, 2) dp[nxt][j][k] = 0x3f3f3f3f; REP(j, n+1) { REP(k, 2) { if(dp[cur][j][k] == 0x3f3f3f3f) continue; if(k == 0) { // Aに選ぶ chmin(dp[nxt][j+1][0], dp[cur][j][k] - t[i-1] + t[i]); // Bに選ぶ chmin(dp[nxt][j][1], dp[cur][j][k] + t[i]); } else { chmin(dp[nxt][j+1][0], dp[cur][j][k] + t[i]); chmin(dp[nxt][j][1], dp[cur][j][k] - t[i-1] + t[i]); } } } cur = !cur, nxt = !nxt; } cout << min(dp[cur][n/2][0], dp[cur][n/2][1]) << endl; return 0; }