首页 > 代码库 > ZOJ 3802 Easy 2048 Again(状压dp)
ZOJ 3802 Easy 2048 Again(状压dp)
这道题的意思就是:2048游戏变成了只有一行的时候的玩法,可以向左合并。给你一串数字你可以选择一些加入队列,和为每个数的和,加上合并成的数字。
解题思路:如果一个序列可以合并那么它一定是降序的,比如:32,16,8,4否则的话,他是不能合并的此时的和就确定了。比如32, 32, 8,16.后面的16怎么合并都会比8大,所以是16之前的数字不可能继续合并下去。通过分析我们可以知道降序序列最多会有12种组合。4096……2.所以每次的时候状压这种状态,每个数字每次有两个选择,放入或者并不放入队列当中。在放的时候在枚举前一种的状态推到下一个状态。
如果当前数字比上一个状态中最小的数字小的话,就可以把这个数字加入这个状态中,如果大那就这个状态不会向下推出新状态了,新状态的开始也就是x了。(这里状压的序列是降序的所以从最小的枚举就可以了。)相同就不断的进行合并。
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 canonly 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
Hint
In the third sample case, Dark_sun will choose {8,4,4,8,4,2,2}. Firstly, the first three treasures will be combined to 16 and then the {16,8,4,2,2} will become 32. And he will get the basic score 32(8+4+4+8+4+2+2) and the bonus score 84(8+16+4+8+16+32).
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #include <stdio.h> #include <string> #include <queue> #include <cmath> #include <stack> #include <map> #include <set> #define eps 1e-10 ///#define M 1000100 ///#define LL __int64 #define LL long long ///#define INF 0x7ffffff #define INF 0x3f3f3f3f #define PI 3.1415926535898 #define zero(x) ((fabs(x)<eps)?0:x) using namespace std; const int maxn = 510; int dp[510][8016]; int num[maxn]; void change(int s, int ss, int k, int x) { if(k == 0) { dp[s][x] = max(dp[s][x], dp[ss][0]+x); return; } if(dp[ss][k] == 0) return; dp[s][k] = max(dp[s][k],dp[ss][k]); int y = x; int ans = x; for(int i = 0; i < 13; i++) { int now = (1<<i); if((k&now) == 0) continue; if(now < y) dp[s][x] = max(dp[ss][k]+x, dp[s][x]); if(now > y) dp[s][x+k] = max(dp[s][x+k], dp[ss][k]+ans); if(now != y) return ; y *= 2; ans += y; } dp[s][y] = max(dp[s][y], dp[ss][k]+ans); } int main() { int T; cin >>T; while(T--) { int n; scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%d",&num[i]); for(int i = 0; i <= n; i++) for(int j = 0; j <= 8000; j++) dp[i][j] = 0; dp[1][num[1]] = num[1]; for(int i = 2; i <= n; i++) for(int j = 0; j <= 8000; j++) change(i, i-1, j, num[i]); int Max = 0; for(int i = 0; i <= 8000; i++) Max = max(dp[n][i], Max); cout<<Max<<endl; } return 0; }
ZOJ 3802 Easy 2048 Again(状压dp)