zoj 3802 Easy 2048 Again (动态规划)
2014-08-27 12:49
204 查看
题目大意:
有一串由 2 4 8 16 组成的数字,要求从左往右依次取 若干个数字,使得最后的价值最大。获得的价值有两部分组成,一个是加进去的价值,另外一个是合并后的价值,跟2048相似的地方是如果两个相邻的数字一样,那么他们就会合并。比如:对于数组 2 8 4 8 如果选择 2 8 4 8 那么他的价值就是2+8+4+8 = 22(因为没有可以合并的数字)但是,如果选择2 8 8(就是对于数字4不选择) 那么他的价值就是 2+8+8 + 16 = 34 (前面的2+8+8是加进去的数字的和,后面的16是相邻两个数合并后的值)
。对于2 8 4 8 这组数据,34的价值最大,所以输出34.
解题思路:
这是一道状态压缩的动态规划题目。从题目的描述中,我们可以看到:如果加进去的一个数字,比他前面的一个数字要大,那么他就不可能与前面的数字进行合并。然后,我们可以用dp[len][num] 来表示相应的值,其中第一位 len 表示 当前是第 len 个数字。第二位的num 用二进制的形式保存,如果num的值是 0110 就表示当前保存的数字是 X 4 2 其中。我们的dp 里面保存的是连续递减的数。相应的状态转移方程就变成了:
1.如果当前这个数字比它前面的一个数字大,那么num就变成它;
2.如果当前这个数字跟它前面一个数字一样,也就是说,这个数字可以进行合并,那么就合并它,num值变成合并后的dp里面递减的数字,直到不能进行合并为止,dp加上相对应的价值;
3.如果当前这个数字比它前面的一个数字小,也就是说,这个数字可以跟前面的状态形成递减,那么相应的dp就有num状态转移到num|x 状态 其中x表示当前这个数字。
4.我这边的dp值如果等于 -1 表示该状态不能达到
由于最多只有500个数字,即使每个数字都是16最大也就8000 所以,num 开成8300 就足够了。
这个题目时间限制比较紧,所以memset 一下子初始化所有的dp值会超时,如果我们每次都初始化一维效果可能会好很多。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
int dp[555][8300];
int main()
{
int T,n,m,i,j;
int a[555];
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(dp[0],-1,sizeof(dp[0]));
dp[0][0]=0;
for(i=1; i<=n; i++)
{
memset(dp[i],-1,sizeof(dp[i]));
for(j=0; j<=8200; j+=2)
{
//如果之前这个状态是不能达到的那么就跳过
if(dp[i-1][j]==-1)continue;
//该数比它前面一个数字大
if(((a[i]-1)&j)!=0) dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+a[i]);
//该数恰好可以与它前面一个数字合并
else if((a[i]&j)!=0 )
{
int tem = a[i];
int sum = tem ;
int xx=j;
while((tem&xx)!=0)
{
xx=xx-tem;
tem = tem<<1;
sum += tem ;
}
dp[i][xx|tem] = max (dp[i][xx|tem],dp[i-1][j]+sum);
}
else dp[i][j|a[i]]=max(dp[i][j|a[i]],dp[i-1][j]+a[i]);
}
for(j=0; j<8200; j+=2)
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
int ans =0;
for(j=0; j<8200; j+=2)
ans=max(ans,dp
[j]);
printf("%d\n",ans);
}
return 0;
}
有一串由 2 4 8 16 组成的数字,要求从左往右依次取 若干个数字,使得最后的价值最大。获得的价值有两部分组成,一个是加进去的价值,另外一个是合并后的价值,跟2048相似的地方是如果两个相邻的数字一样,那么他们就会合并。比如:对于数组 2 8 4 8 如果选择 2 8 4 8 那么他的价值就是2+8+4+8 = 22(因为没有可以合并的数字)但是,如果选择2 8 8(就是对于数字4不选择) 那么他的价值就是 2+8+8 + 16 = 34 (前面的2+8+8是加进去的数字的和,后面的16是相邻两个数合并后的值)
。对于2 8 4 8 这组数据,34的价值最大,所以输出34.
解题思路:
这是一道状态压缩的动态规划题目。从题目的描述中,我们可以看到:如果加进去的一个数字,比他前面的一个数字要大,那么他就不可能与前面的数字进行合并。然后,我们可以用dp[len][num] 来表示相应的值,其中第一位 len 表示 当前是第 len 个数字。第二位的num 用二进制的形式保存,如果num的值是 0110 就表示当前保存的数字是 X 4 2 其中。我们的dp 里面保存的是连续递减的数。相应的状态转移方程就变成了:
1.如果当前这个数字比它前面的一个数字大,那么num就变成它;
2.如果当前这个数字跟它前面一个数字一样,也就是说,这个数字可以进行合并,那么就合并它,num值变成合并后的dp里面递减的数字,直到不能进行合并为止,dp加上相对应的价值;
3.如果当前这个数字比它前面的一个数字小,也就是说,这个数字可以跟前面的状态形成递减,那么相应的dp就有num状态转移到num|x 状态 其中x表示当前这个数字。
4.我这边的dp值如果等于 -1 表示该状态不能达到
由于最多只有500个数字,即使每个数字都是16最大也就8000 所以,num 开成8300 就足够了。
这个题目时间限制比较紧,所以memset 一下子初始化所有的dp值会超时,如果我们每次都初始化一维效果可能会好很多。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
int dp[555][8300];
int main()
{
int T,n,m,i,j;
int a[555];
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
scanf("%d",&a[i]);
memset(dp[0],-1,sizeof(dp[0]));
dp[0][0]=0;
for(i=1; i<=n; i++)
{
memset(dp[i],-1,sizeof(dp[i]));
for(j=0; j<=8200; j+=2)
{
//如果之前这个状态是不能达到的那么就跳过
if(dp[i-1][j]==-1)continue;
//该数比它前面一个数字大
if(((a[i]-1)&j)!=0) dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+a[i]);
//该数恰好可以与它前面一个数字合并
else if((a[i]&j)!=0 )
{
int tem = a[i];
int sum = tem ;
int xx=j;
while((tem&xx)!=0)
{
xx=xx-tem;
tem = tem<<1;
sum += tem ;
}
dp[i][xx|tem] = max (dp[i][xx|tem],dp[i-1][j]+sum);
}
else dp[i][j|a[i]]=max(dp[i][j|a[i]],dp[i-1][j]+a[i]);
}
for(j=0; j<8200; j+=2)
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
int ans =0;
for(j=0; j<8200; j+=2)
ans=max(ans,dp
[j]);
printf("%d\n",ans);
}
return 0;
}
相关文章推荐
- ZOJ-3802-Easy 2048 Again【状态压缩dp】【位运算】【好题】
- zoj-3802-Easy 2048 Again
- ZOJ 3802 Easy 2048 Again 状态压缩dp
- [zoj 3802]Easy 2048 Again 状压DP
- ZOJ3802 Easy 2048 Again (状压DP)
- ZOJ-3802:Easy 2048 Again(2048游戏 状态压缩dp)
- ZOJ 3802 Easy 2048 Again 状态DP
- ZOJ 3802 Easy 2048 Again 状压DP
- ZOJ 3802 Easy 2048 Again(压缩dp)
- ZOJ 3802 Easy 2048 Again 状压DP
- Easy 2048 Again - ZOJ 3802 状压dp
- zoj 3802 Easy 2048 Again (14.8 浙大月赛 E)
- ZOJ 3802 Easy 2048 Again 像缩进DP
- ZOJ:3802 Easy 2048 Again (状态压缩)
- 【DP】 ZOJ 3802 Easy 2048 Again
- zoj 3802 Easy 2048 Again(状压DP)
- ZOJ 3802 Easy 2048 Again(状压DP+位运算)【一维状压类模板--2048】
- ZOJ -- 3802 Easy 2048 Again(状压dp)
- ZOJ 3802 Easy 2048 Again(状压DP)
- Easy 2048 Again - ZOJ 3802 像缩进dp