Google Code Jam 2013 – Round 1A Problem B


You’ve got a very busy calendar today, full of important stuff to do. You worked hard to prepare and make sure all the activities don’t overlap. Now it’s morning, and you’re worried that despite all of your enthusiasm, you won’t have the energy to do all of this with full engagement.

You will have to manage your energy carefully. You start the day full of energy – E joules of energy, to be precise. You know you can’t go below zero joules, or you will drop from exhaustion. You can spend any non-negative, integer number of joules on each activity (you can spend zero, if you feel lazy), and after each activity you will regain R joules of energy. No matter how lazy you are, however, you cannot have more than E joules of energy at any time; any extra energy you would regain past that point is wasted.

Now, some things (like solving Code Jam problems) are more important than others. For the ith activity, you have a value vi that expresses how important this activity is to you. The gain you get from each activity is the value of the activity, multiplied by the amount of energy you spent on the activity (in joules). You want to manage your energy so that your total gain will be as large as possible.

Note that you cannot reorder the activities in your calendar. You just have to manage your energy as well as you can with the calendar you have.

Input

The first line of the input gives the number of test cases, T. T test cases follow. Each test case is described by two lines. The first contains three integers: E, the maximum (and initial) amount of energy, R, the amount you regain after each activity, and N, the number of activities planned for the day. The second line contains N integers vi, describing the values of the activities you have planned for today.

Output

For each test case, output one line containing “Case #x: y”, where x is the case number (starting from 1) and y is the maximum gain you can achieve by managing your energy that day.

Limits

1 ≤ T ≤ 100.

Small dataset

1 ≤ E ≤ 5.
1 ≤ R ≤ 5.
1 ≤ N ≤ 10.
1 ≤ vi ≤ 10.

Large dataset

1 ≤ E ≤ 107.
1 ≤ R ≤ 107.
1 ≤ N ≤ 104.
1 ≤ vi ≤ 107.

Sample Input
3
5 2 2
2 1
5 2 2
1 2
3 3 4
4 1 3 5

Sample Output
Case #1: 12
Case #2: 12
Case #3: 39

In the first case, we can spend all 5 joules of our energy on the first activity (for a gain of 10), regain 2 and spend them on the second activity. In the second case, we spend 2 joules on the first activity, regain them, and spend 5 on the second. In the third case, our regain rate is equal to the maximum energy, meaning we always recover all energy after each activity – so we can spend full 3 joules on each activity.

Solution

This is similar to the knapsack problem, so I tried to solve it with recursion and memoization. My solution managed to solve the small input, but it failed at the large one (the possible values of the input were too large). Anyway here’s my approach (the version below is not using memoization, as it was geared to solve the small input, so it wouldn’t be necessary):

#include <stdio.h>

int ac[10];
int r, n, e;

int process(int current, int pos){
        int max = 0;
        int i;
        int partial;
        if(pos==n)
                return 0;

        if(pos>0)
                current+=r;
        if(current>e)
                current=e;

        for(i=0;i<=current;i++){
                partial = i*ac[pos] + process(current-i,pos+1);
                if(partial>max)
                        max = partial;
        }
        return max;

}

int main(){
        int t,k;
        int i;

        scanf("%d",&t);

        for(k=0;k<t;k++){
                scanf("%d %d %d",&e,&r,&n);

                for (i=0;i<n;i++)
                        scanf("%d",&ac[i]);

                printf("Case #%d: %d",k+1,process(e,0));
                if(k<t-1)
                        printf("n");
        }

return 0;
}

And here’s a solution from another user which solves the problem quite elegantly. It basically runs through an array of “spent energy” optimizing it according to the value to be gained on the respect tasks:

const int maxn = 10000 + 5;

int N;
long long E, R, v[maxn], u[maxn];

int main()
{
    freopen("b2.in", "r", stdin);
    freopen("b2.out", "w", stdout);

    int t2;
    cin >> t2;
    for (int t1 = 1; t1 <= t2; ++t1) {
        printf("Case #%d: ", t1);
        cin >> E >> R >> N;
        if (R > E)
            R = E;
        for (int i = 1; i <= N; ++i)
            cin >> v[i];
        u[1] = E;
        for (int i = 2; i <= N; ++i) {
            u[i] = R;
            for (int j = i - 1; j >= 1; --j) {
                if (v[j] >= v[i])
                    break;
                if (u[j] + u[i] <= E) {
                    u[i] += u[j];
                    u[j] = 0;
                }else {
                    u[j] -= E - u[i];
                    u[i] = E;
                    break;
                }
            }
        }
        long long ret = 0;
        for (int i = 1; i <= N; ++i)
            ret += u[i] * v[i];
        cout << ret;
        printf("n");
    }
    
    return 0;
}

One thought on “Google Code Jam 2013 – Round 1A Problem B

  1. Portal Kobiet

    Do you mind if I quote a few of your articles as long as I provide
    credit and sources back to your webpage? My blog is in the exact same niche as
    yours and my users would truly benefit from some of
    the information you provide here. Please let me know if
    this alright with you. Thanks!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *