ZOJ-3802-Easy 2048 Again【状态压缩dp】【位运算】【好题】

3802-Easy 2048 Again

Dark_sun knows that on a single-track road (which means once he passed this area, he cannot come back again), there are some underground treasures on each area of the road which has the value of 2, 4, 8 or 16. Dark_sun can decide whether to dig them or not in order to get the highest score. The calculation rule of the total score is similar to the game Flappy 2048.

Dark_sun’s bag is like a queue. When he gets a treasure, the treasure will be pushed back into the end of the bag. And the score will add the value of the treasure. For example, when there are treasures on the road in the order of {2, 8, 4, 8} and if Dark_sun decides to dig all of them, he will get the final score of 2+8+4+8=22. And his bag will finally become the sequence of {2, 8, 4, 8}.

If the adjacent treasures in the Dark_sun’s bag have the same value, they will mix into a bigger treasure which has the value of their sum (the double value of the previous one). And Dark_sun will get a combo score of the value of bigger treasure. For example in the previous case, if Dark_sun decides to dig only the {2, 8, 8} treasure in sequence. He will get the basic score of 18(2+8+8). And when the last treasure (value 8) is pushed back into his bag, his bag will turn {2, 8, 8} into {2, 16} and he will get a bonus score of 16. And his final score will become 18+16=34 (which is the best strategy in this case.)

Notice that the treasures mix to the bigger one automatically when there are the same adjacent treasures. For example, when there are treasures of {2, 2, 4, 8, 16} on the road, and if Dark_sun decides to dig all of them, he will get the basic score of 32(2+2+4+8+16) and a bonus score of 60(4+8+16+32). At last he will get the total score of 92 and the bag becomes {32}.

Now, Dark_sun wants to get the highest score (no matter what’s the treasure in his bag), can you tell him the what’s the highest score?

Input

The first line is an integer n, which is the case number. In each case, the first line is an integer L, which is the length of the road.(0 < L ≤ 500) The second line contains L integers which can only be 2, 4, 8 or 16. This means the value of treasure on each area of the road.

Output

For each case, you should output an integer. The answer is the maximum of the total score which Dark_sun may get.

Sample Input

3
4
2 8 4 8
5
2 2 4 8 16
8
8 4 4 2 8 4 2 2
Sample Output

34
92
116

题目链接:ZOJ-3802

题目大意:一个一维的2048游戏只要有相邻的相同就会合并,合并之后会有奖励分数,总共n个,每个都可以取或者不取。问最终得到的最大值

数据范围n<=500 , a[i]={2,4,8,16};

题目思路:状态压缩dp,利用滚动数组优化。参考了别人的博客,写了自己的理解,不知道有没有理解错orz,感觉很巧妙。

参考博客: here

以下是代码:

//
// zoj-3802-Easy 2048 Again.cpp
// ZOJ
//
// Created by pro on 16/4/15.
// Copyright (c) 2016年 pro. All rights reserved.
//

#include <iostream>
#include<stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
int num[10005];
int n;
int dp[2][10005];
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        scanf("%d",&n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&num[i]);
        }
        memset(dp, -1, sizeof(dp));
        dp[0][0] = 0;
        int pos = 1;
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < 4096 * 2; j++)
            {
                if (dp[pos ^ 1][j] == -1) continue;
                dp[pos][j] = max(dp[pos][j],dp[pos ^ 1][j]);   //不取第i个数字
                ans = max(ans,dp[pos][j]);
                int sum = num[i];  //刚开始为最小值
                int t = j;  //假设为 0111001
                //因为数字都是2的倍数,所以状态为类似于0001000(只含有一个1),减一之后变成0000111(原来为1的变成0,接下来的都是1)这样 & 操作 == 0, 即表示 j 状态不含有比num[i]小的数字
                if((t & (num[i] - 1)) == 0)
                {
                    //接下来进行合并操作
                    int k = num[i];  //记录当前值
                    while (k & t)
                    {
                        sum += (k << 1);  //sum值加上当前值*2
                        k <<= 1;  //当前最小值*2;
                    }

                    t&=~(k-1);   //k-1即 0100000-> 0011111, ~(k-1)即 1100000, t&=~(k-1)即 0100000,只保留大于等于k的位数
                    t |= k;  //考虑如果第k位原来为0的情况,则加上

                }
                else t = num[i];
                dp[pos][t] = max(dp[pos][t],dp[pos^1][j] + sum);
                ans = max(ans,dp[pos][t]);
            }
            pos ^= 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(位运算,dp,ZOJ,3802)