+1 vote

You are given k stacks, of n coins each.  The value of i-th coin in j-th stack is given by v[i][j].

You play a game against an opponent by alternating turns. In each turn, a player selects one of the top coins (the coin at the highest location of the stack), removes it permanently, and receives the value of the coin. In each move, each person removes one coin only, and can not remove a coin that is not at the top of its stack.

Design an algorithm to maximize the money value you can win if you move first.

in Dynamic Programming by AlgoMeister (1.6k points)

2 Answers

+1 vote

Notation:

Let MCV (H1, H2, H3, …, Hk) denote the maximum coin value that we can obtain from the given k stacks coins. Hi means the height of the i-th stack. Further, let S (H1, H2, H3, …, Hk) denote the sum of the values for all coins in the k stacks.

Recursive Formulation:

We observe that once the first player pockets one of the top coins in these k stacks, the opponent realizes the maximum value from the remaining coins.  Therefore, the value realized by the first player is the sum of all k stacks minus the value realized by the opponent.  Therefore, we can write MCV (H1, H2, H3, …, Hk) as:

∀ H> 0 {1≤ i ≤k}

MCV (H1, H2, H3, …, Hk) = max {S (H1, H2, H3, …, Hk) - MCV (H1-1, H2, H3, …, Hk), MCV (H1, H2-1, H3, …, Hk), MCV (H1-1, H2, H3-1, …, Hk),…, MCV (H1-1, H2, H3, …, Hk-1) }

This can further be written as:

MCV (H1, H2, H3, …, Hk) = S (H1, H2, H3, …, Hk) – min {MCV (H1-1, H2, H3, …, Hk), MCV (H1, H2-1, H3, …, Hk), MCV (H1, H2, H3-1, …, Hk),…, MCV (H1, H2, H3, …, Hk-1) }

The base case of the recurrence can be set as MCV (0, 0, …,0) = 0, S (0, 0, …,0) = 0.

Algorithm:

The challenge is that we cannot build a k dimensions array like MCV [H1] [ H2] [ H3] …[Hk]. So we transform the k dimensions to one dimension.

//Initailize

int kn=(int) (Math.pow((n+1),k));

int MCV[]=new int[kn];

int S[]=new int[kn];

//Base case

MCV[0]=0;
S[0]=0;
for (int i=1;i<kn;i++){
  int[] h=new int[k];//h[] are the height of k stacks
  for (int j=0;j<k;j++){
    int division=(int)Math.pow((n+1),j);
    int mod=i/division;
    h[j]=mod%(n+1);
  }

  for(int j=0;j<k;j++){
    if(h[j]>0){
       S[i]=S[i-(int)Math.pow((n+1),j)]+v[j][h[j]];
       break;}
    }
  int min=Integer.MAX_VALUE;
  for(int j=0;j<k;j++){
    if(h[j]>0){
       if(MCV[i-(int)Math.pow((n+1),j)]<min){
          min=MCV[i-(int)Math.pow((n+1),j)];
        }
     }
  }
  MCV[i]=S[i]-min;
}

Time Complexity:

O(n) is kn*k, kn is Math.pow((n+1),k). So, O(n) = k*nk

by (136 points)
edited by
0 votes
Notation: Let MCV(V, i, j) denote the maximum coin value that we can obtain given the list of coins V[i..j] .  Further, let S(V,i,j) denote the sum of the values of all the coins in V[i..j] .
Recursive Formulation: We observe that once the first player pockets the first or the last coin, the opponent realizes the maximum value from the remaining list. Therefore, the value realized by the first player is the sum of the list minus the value realized by the opponent.  Therefore, we can write MCV(V,i,j) as:
MCV(V,i,j)=  ma x {S(V,i,j) – MCV(V – v i ), S(V,i,j) MCV(V – v j )}
This can further be written as: MCV(V,i,j)=S(V,i,j) – mi n {MCV(V – v i ), MCV(V – v j ) }
The base case of the recurrence can be set as MCV(φ) = 0 , or equivalently that the value that can be realized by a single element list is the value of that element.
Algorithm: This algorithm works like many other algorithms that need to “grow” the range of the array.  Specifically, the iterations can work as follows:
Notation: Let MCV(V, i, j) denote the maximum coin value that we can obtain given the list of coins V[i..j] .  Further, let S(V,i,j) denote the sum of the values of all the coins in V[i..j] .
Recursive Formulation: We observe that once the first player pockets the first or the last coin, the opponent realizes the maximum value from the remaining list. Therefore, the value realized by the first player is the sum of the list minus the value realized by the opponent.  Therefore, we can write MCV(V,i,j) as:
MCV(V,i,j)=  ma x {S(V,i,j) – MCV(V – v i ), S(V,i,j) MCV(V – v j )}
This can further be written as: MCV(V,i,j)=S(V,i,j) – mi n {MCV(V – v i ), MCV(V – v j ) }
The base case of the recurrence can be set as MCV(φ) = 0 , or equivalently that the value that can be realized by a single element list is the value of that element.
Algorithm: This algorithm works like many other algorithms that need to “grow” the range of the array.  Specifically, the iterations can work as follows:
double[][] S = new double[n][n];

double[][] MCV = new double[n][n];

// Initialize S[i,i] = V[i]

// Initialize MCV[i,i] = V[i]

for i=0 to n-2

for j=i+1 to n-1

S[i,j]=S[i,j-1]+V[j]

for k=1 to n-1

for i=0 to n-2

MCV[i,i+k] = S[i,i+k] - min{MCV[i+1,i+k], MCV[i,i+k-1]}
by AlgoMeister (688 points)

Related questions

0 votes
2 answers
asked Apr 25, 2023 in Probability by Amrinder Arora AlgoMeister (1.6k points)
0 votes
1 answer
+4 votes
1 answer
asked Jun 20, 2017 in Dynamic Programming by Baijun Xie AlgoStar (416 points)
The Book: Analysis and Design of Algorithms | Presentations on Slideshare | Lecture Notes, etc
...