AOJ2510 Twin book report
問題
方針
まず読み終える時間を最短にしないといけないのに注意. なのでアミもマミも全ての本を読んだ後にまとめて書くのが最適. そのときの答えは $\sum r[i] + \sum w[i]$ になる. けど,最も大きい $r[i]$ が,$\sum r[i] / 2$ より大きいとき,その戦略ができない (問題文中の図の例). そのときは,アミは最長の本を読む→他の本を全て読む→書く,マミは最長以外の本を全て読む→間の時間に少し書く→最長の本を読む→残りを書くという戦略が最適. 間の時間になるべく無駄な時間を作らないように DP をする.これは TDPC の A 問題と似た感じでやる.
実装
#include <bits/stdc++.h>
using namespace std;
int n;
int r[1010], w[1010];
int dp[1000010];
int main(){
cin.tie(0);
ios_base::sync_with_stdio(0);
while(cin >> n && n){
int sum_r = 0, sum_w = 0, max_r = 0;
for(int i = 0; i < n; ++i){
cin >> r[i] >> w[i];
if(r[max_r] < r[i]){
max_r = i;
}
sum_r += r[i];
sum_w += w[i];
}
if(r[max_r] * 2 <= sum_r){
cout << sum_r + sum_w << endl;
} else {
swap(r[n-1], r[max_r]);
swap(w[n-1], w[max_r]);
int rem = r[n-1]*2 - sum_r;
fill(dp, dp+rem+10, 0);
dp[0] = true; // mudanazikannni tsumekomi
for(int i = 0; i < n-1; ++i){
for(int j = rem; j >= w[i]; --j){
dp[j] |= dp[j-w[i]];
}
}
int dead = -1;
for(int i = rem; i >= 0; --i){
if(dp[i]){
dead = rem - i;
break;
}
}
cout << sum_r + sum_w + dead << endl;
}
}
}