Consider the following two-player game played with a sequence of N positive integers (2 <= N <= 100) laid onto a game board. Player 1 starts the game. The players move alternately by selecting a number from either the left or the right end of the sequence. That number is then deleted from the board, and its value is added to the score of the player who selected it. A player wins if his sum is greater than his opponents.
Write a program that implements the optimal strategy. The optimal strategy yields maximum points when playing against the "best possible" opponent. Your program must further implement an optimal strategy for player 2.
| Line 1: | N, the size of the board |
| Line 2-etc: | N integers in the range (1..200) that are the contents of the game board, from left to right |
6 4 7 2 9 5 2
Two space-separated integers on a line: the score of Player 1 followed by the score of Player 2.
18 11
思路:sum[i][j]表示i到j的和,f[i][j]表示i到j先取人的最大和。
f[i][j]=max(sum[i][j-1]-f[i][j-1]+shu[j],sum[i+1][j]-f[i+1][j]+shu[i]);
因为先手最优,答案就是确定的,别被题目给蒙住。
/*
ID:nealgav1
LANG:C++
PROG:game1
*/
#include<fstream>
#include<cstring>
using namespace std;
ifstream cin("game1.in");
ofstream cout("game1.out");
const int mm=1000;
int f[mm][mm],sum[mm][mm];
int shu[mm];
int main()
{
int n;
while(cin>>n)
{
for(int i=1;i<=n;i++)cin>>shu[i];
memset(sum,0,sizeof(sum));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{for(int j=i;j<=n;j++)
sum[i][j]=sum[i][j-1]+shu[j];
f[i][i]=shu[i];
}
for(int i=n-1;i>=1;i--)
{ for(int j=i+1;j<=n;j++)
{
f[i][j]=max(sum[i][j-1]-f[i][j-1]+shu[j],sum[i+1][j]-f[i+1][j]+shu[i]);
}
}
cout<<f[1][n]<<" "<<sum[1][n]-f[1][n]<<"\n";
}
}
We use dynamic programming to determine, for every possible piece of board that could be left at any point in the game, how many points the best strategy gets for the winner, and how many for the loser.
Let us define best[board] to be the highest score we can hope to get by going first starting with the given board.
If we are looking at a board "a ... b", the best number of points is the maximum of the following:
a + total[... b] - best[... b]
b + total[a ...] - best[a ...]
We use total[board] - best[board] as the best that we can hope to do going second starting with the given board.
If we are looking at the board "a", the best number of points is a.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAXBOARD 100
int board[MAXBOARD];
/*
* best and total are indexed so that (e.g.) best[i, l] refers
* to the board of length l starting at place i.
*/
int total[MAXBOARD][MAXBOARD];
int best[MAXBOARD][MAXBOARD];
int
max(int a, int b)
{
return a > b ? a : b;
}
void
main(void)
{
FILE *fin, *fout;
int j, l, n;
fin = fopen("game1.in", "r");
fout = fopen("game1.out", "w");
assert(fin != NULL && fout != NULL);
fscanf(fin, "%d", &n);
for(j=0; j<n; j++)
fscanf(fin, "%d", &board[j]);
/* calculate subboard totals */
for(j=0; j<n; j++)
total[j][0] = 0;
for(l=1; l<=n; l++)
for(j=0; j+l<=n; j++)
total[j][l] = board[j] + total[j+1][l-1];
/* calc best for boards of size one */
for(j=0; j+1<=n; j++)
best[j][1] = board[j];
/* calc best for bigger boards */
for(l=2; l<=n; l++)
for(j=0; j+l<=n; j++)
best[j][l] = max(board[j] + total[j+1][l-1] - best[j+1][l-1],
board[j+l-1] + total[j ][l-1] - best[j ][l-1]);
fprintf(fout, "%d %d\n", best[0][n], total[0][n]-best[0][n]);
exit(0);
}
Nick Pilkington of South Africa writes:
You only need O(n) space for the sum not O(n*n). This eliminates extra calculation as it can be computed during input. This also means that the board values don't need to be stored at all, leading to a much tighter solution:
#include <fstream>
using namespace std;
#define min(a,b) ((a<b)?a:b)
ifstream fin("game1.in");
ofstream fou("game1.out");
int n;
int sum[101];
int best[101][101];
void main()
{
fin >> n;
for(int i = 1; i <= n; i++) {
fin >> best[i][i];
sum[i] = sum[i-1] + best[i][i];
}
for(int i = 1; i <= n; i++)
for(int j = 1; j+i <= n; j++)
best[j+i][j] = sum[j+i]-sum[j-1] - min(best[j+i-1][j], best[j+i][j+1]);
fou << best[n][1] << " " << sum[n] - best[n][1] << endl;
}
Lucian Boca Romania writes:
I propose some memory optimizations for "A Game" problem.
The algorithm is the same, I simulate the calculation of the matrix best[i][l] = the best score wich can be obtained by the first player with the board pieces i,i+1,...,i+l-1 (a sequence of numbers starting with position i and having the length l). I also simulate the calculation of the matrix total[i][l] = the sum of all elements in the sequence starting with position i and having the length l. The reccurence relation is:
best[i][l]=total[i][l] - min( best[i+1][l-1], best[i][l-1] )
and our goal is to obtain best[1][n]
The optimizations:
Here's the code:
#include <stdio.h>
#define NMAX 101
int best[NMAX][2], t[NMAX];
int n;
void
readx () {
int i, aux;
freopen ("game1.in", "r", stdin);
scanf ("%d", &n);
for (i = 1; i <= n; i++) {
scanf ("%d", &aux);
t[i] = t[i - 1] + aux;
}
fclose (stdin);
}
inline int
min (int x, int y) {
return x > y ? y : x;
}
void
solve () {
int i, l;
for (l = 1; l <= n; l++)
for (i = 1; i + l <= n + 1; i++)
best[i][l%2] = t[i + l - 1] - t[i - 1] - min (best[i + 1][(l - 1) % 2],
best[i][(l - 1) % 2]);
}
void writex () {
freopen ("game1.out", "w", stdout);
printf ("%d %d\n", best[1][n % 2], t[n] - best[1][n % 2]);
fclose (stdout);
}
int
main () {
readx ();
solve ();
writex ();
return 0;
}
USER: Neal Gavin Gavin [nealgav1]
TASK: game1
LANG: C++
Compiling...
Compile: OK
Executing...
Test 1: TEST OK [0.011 secs, 11172 KB]
Test 2: TEST OK [0.011 secs, 11172 KB]
Test 3: TEST OK [0.011 secs, 11172 KB]
Test 4: TEST OK [0.011 secs, 11172 KB]
Test 5: TEST OK [0.011 secs, 11172 KB]
Test 6: TEST OK [0.011 secs, 11172 KB]
Test 7: TEST OK [0.011 secs, 11172 KB]
Test 8: TEST OK [0.011 secs, 11172 KB]
Test 9: TEST OK [0.011 secs, 11172 KB]
Test 10: TEST OK [0.011 secs, 11172 KB]
Test 11: TEST OK [0.011 secs, 11172 KB]
Test 12: TEST OK [0.011 secs, 11172 KB]
Test 13: TEST OK [0.011 secs, 11172 KB]
Test 14: TEST OK [0.011 secs, 11172 KB]
Test 15: TEST OK [0.011 secs, 11172 KB]
Test 16: TEST OK [0.011 secs, 11172 KB]
All tests OK.
YOUR PROGRAM ('game1') WORKEDFIRST TIME! That's fantastic
-- and a rare thing. Please accept these special automated