USACO 2010 Gold January P1. Taking Turns

Problem 1: Taking Turns [John Pardon, 2009]

Farmer John has invented a new way of feeding his cows. He lays out N (1 <= N <= 700,000) hay bales conveniently numbered 1..N in a long line in the barn. Hay bale i has weight W_i (1 <= W_i <= 2,000,000,000). A sequence of six weights might look something like:

    17 5 9 10 3 8

A pair of cows named Bessie and Dessie walks down this line after examining all the haybales to learn their weights. Bessie is the first chooser. They take turns picking haybales to eat as they walk (once a haybale is skipped, they cannot return to it). For instance, if cows Bessie and Dessie go down the line, a possible scenario is:

  • Bessie picks the weight 17 haybale
  • Dessie skips the weight 5 haybale and picks the weight 9 haybale
  • Bessie picks the weight 10 haybale
  • Dessie skips the weight 3 haybale and picks the weight 8 haybale

Diagrammatically:

Bessie   |      |  
        17 5 9 10 3 8  
Dessie       |      |  

This scenario only shows a single skipped bale; either cow can skip as many as she pleases when it’s her turn.

Each cow wishes to maximize the total weight of hay she herself consumes (and each knows that the other cow has this goal). Furthermore, a cow will choose to eat the first bale of hay that maximimizes her total weight consumed.

Given a sequence of hay weights, determine the amount of hay that a pair of cows will eat as they go down the line of hay.

PROBLEM NAME: hayturn

INPUT FORMAT:

  • Line 1: A single integer: N

  • Lines 2..N+1: Line i+1 contains a single integer: W_i

SAMPLE INPUT (file hayturn.in):

6
17
5
9
10
3
8

OUTPUT FORMAT:

  • Line 1: Two space-separated integers, the total weight of hay consumed by Bessie and Dessie respectively

SAMPLE OUTPUT (file hayturn.out):

27 17

Solution

Game theory using DP, going from backward. Each state consists of two values for first player and second player. State transition function

for i in N-1 to 0
  for j in 1 to N - 1 - i:
    dp[i] = max(dp[i + j], {weights[j] + dp[i + j].second, dp[i + j].first});

This is a O(N^2) solution, and can be optimized to O(N) since the max value can be piggy backed.

for i in N-1 to 0:
  dp[i] = max(dp[i + 1], {weights[i] + dp[i + 1].second, dp[i + 1].first});
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
#include <bits/stdc++.h>
using namespace std;

int N;
vector<long long> weights;

int main() {
    cin >> N;
    weights.resize(N);

    for (int i = 0; i < N; i++) {
        cin >> weights[i];
    }

    vector<pair<long long, long long>> dp(N + 1);

    //put a fake initialization at N as position N-1 has haybales
    dp[N] = {0, 0};

    for (int i = N - 1; i >= 0; i--) {
        dp[i] = max(dp[i + 1], {weights[i] + dp[i + 1].second, dp[i + 1].first});
    }

    cout << dp[0].first << " " << dp[0].second;
}