Sicily 1176 Two Ends

1176. Two Ends

Constraints

Time Limit: 1 secs, Memory Limit: 64 MB

Description

In the two-player game "Two Ends", an even number of cards is laid out in a row. On each card, face up, is written a positive integer. Players take turns removing a card from either end of the row and placing the card in their pile. The player whose cards add up to the highest number wins the game. Now one strategy is to simply pick the card at the end that is the largest -- we'll call this the greedy strategy. However, this is not always optimal, as the following example shows: (The first player would win if she would first pick the 3 instead of the 4.) 
3 2 10 4 
You are to determine exactly how bad the greedy strategy is for different games when the second player uses it but the first player is free to use any strategy she wishes.

Input

There will be multiple test cases. Each test case will be contained on one line. Each line will start with an even integer n followed by n positive integers. A value of n = 0 indicates end of input. You may assume that n is no more than 1000. Furthermore, you may assume that the sum of the numbers in the list does not exceed 1,000,000.

Output

For each test case you should print one line of output of the form: 
In game m, the greedy strategy might lose by as many as p points. 
where m is the number of the game (starting at game 1) and p is the maximum possible difference between the first player's score and second player's score when the second player uses the greedy strategy. When employing the greedy strategy, always take the larger end. If there is a tie, remove the left end.

Sample Input

4 3 2 10 4
8 1 2 3 4 5 6 7 8
8 2 2 1 5 3 8 7 3
0

Sample Output

In game 1, the greedy strategy might lose by as many as 7 points.
In game 2, the greedy strategy might lose by as many as 4 points.
In game 3, the greedy strategy might lose by as many as 5 points.

 

这道题的思路要复杂一点,题目每一次给出一组数字作为一副牌,由你来扮演一个玩家,每一次你需要从这组牌最左边或者最右边抽取一张牌;而另一个虚拟玩家玩法固定,每一次抽取最大值,即最左边大则抽取最左边,最右边大则抽取最右边,题目设定若两边排一样大则虚拟玩家抽取左边的牌。最后的要求是,在你先抽牌的情况下,你需要找出你能把虚拟玩家拉开的最大差距。

这种很多种情况的情境下,我们可以使用动态规划来模拟所有的情况并从中挑选一个最优解进行输出。我们定义二维ans储存所有的解的情况,定义一维数组Num储存数字序列;

然后定义动态规划函数dp(int a,int b),其中a, b分别表示左右边界的牌,玩家每一次选择都有两种情况:选择最左边的牌或最右边的牌。故每一次动态规划都有两种方案:

第一种,玩家选择最左边的牌a,那么虚拟玩家就会进行贪心算法选择剩下的左右边界中最大的那张牌,如果最左边大,则虚拟玩家取走牌a+1,下一次dp序列为a+2到b;如果最右边大,则虚拟玩家取走牌b,下一次dp序列为a+1到b-1;

第二种,玩家选择最右边的牌b,那么虚拟玩家就会进行贪心算法选择剩下的左右边界中最大的那张牌,如果最左边大,则虚拟玩家取走牌a,下一次dp序列为a+1到b-1;如果最右边大,则虚拟玩家取走牌b-1,下一次dp序列为a到b-2;

当然存在一种特殊情况就是,玩家抽牌时若只剩两张牌那么就使用贪心算法选择最大的那张牌,而不需要进行上述分情况讨论。

每一次dp都对上述两种方案进行比较,选择玩家分值比较高的方案对ans[a][b]进行赋值,最终找出最好的方案,按照题目要求进行输出即可。

代码如下:

#include <iostream>
#include <memory.h>
using namespace std;

int Num[1010];//存储输入的数字
int ans[1010][1010];//对每一次决策后结果的存储!

int dp(int a, int b)
{
    int temp1 = 0, temp2 = 0;
    if ((b-a)==1)//到最后只剩下两个数的时候就需要贪婪算法了!
    {
        if (Num[a] > Num[b]) return ans[a][b] = Num[a];
        else                 return ans[a][b] = Num[b];
    }
    
    if (ans[a][b] != -1) return ans[a][b];

    //case1先选取左边的数开始
    if (Num[a+1] >= Num[b]) temp1 += Num[a] + dp(a+2, b);
    else                    temp1 += Num[a] + dp(a+1, b-1);

    //case2选取右边的数开始
    if (Num[a] >= Num[b-1]) temp2 += Num[b] + dp(a+1, b-1);
    else                    temp2 += Num[b] + dp(a, b-2);

    //进行动态规划的决策,即选取和大的数!
    if (temp1 > temp2) ans[a][b] = temp1;
    else               ans[a][b] = temp2;

    return ans[a][b];
}   

int main()
{
    int n, count = 0;
    while (cin >> n && n)
    {
        int sum = 0;
        count++;
        memset(Num, 0, sizeof (Num));
        memset(ans, -1, sizeof(ans));
        for (int i = 1; i <= n; i++)
        {
            cin >> Num[i];
            sum += Num[i];
        }
        int differ1 = dp(1, n);//选手1决策所得的和
        int differ2 = sum - differ1;//选手2决策所得的和
        cout<<"In game "<< count <<", the greedy strategy might lose by as many as "<< differ1 - differ2 <<" points."<<endl;
    }
}

                              

  

posted @ 2016-03-23 00:28  日天大哥哥  阅读(334)  评论(0编辑  收藏  举报