洛谷3146 [USACO16OPEN]248(DP)

题意

给定一个1*n的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。

歪解

记忆化搜索
设f[l][r][x]表示(l,r)能不能合成x这个数,那么就有f[l][r][x]|=f[l][k][x-1]&f[k+1][r][x-1]。
然后从大到小枚举x,再枚举个左端点和右端点,判断一下是否可行。具体实现时,x可以从60开始别问我是怎么知道的

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=250;

int n;
int a[maxn];
int f[maxn][maxn][170];

inline bool dfs(int l,int r,int x)
{
    if(f[l][r][x]==1) return true;
    if(f[l][r][x]==-1) return false;
    for(int k=l;k<r;k++)
        if(dfs(l,k,x-1) && dfs(k+1,r,x-1)) return f[l][r][x]=1;
    f[l][r][x]=-1;
    return false;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        f[i][i][a[i]]=1;
    }
    for(int i=60;i>=0;i--)
        for(int l=1;l<=n;l++)
            for(int r=l;r<=n;r++)
                if(dfs(l,r,i))
                {
                    printf("%d\n",i);
                    return 0;
                }
}

偏解

贪心
能合并就合并的策略是显然的。
对于偶数个数挨在一起的问题是很好解决的;
奇数个数的话要稍微处理一下,让中间那个数为0(或其它特别的都可以),0两边各有一个合并值,意思是要么选左边,要么选右边。
思路还是蛮好的,可以实现一下。

正解

DP
设f[i][x]表示从i开始往右合成一个x的位置,那么有DP方程f[i][x]=f[f[i][x-1]][x-1],也就是从i开始两个x-1合成一个x的意思,不知道为什么很像倍增公式。
初始化的时候f[i][a[i]]=i+1就OK了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=250;
int n,ans=0;
int f[maxn][70];

int main()
{
    int mx=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        f[i][x]=i+1;
    }
    for(int j=1;j<=60;j++)
        for(int i=1;i<=n;i++)
        {
            if(f[i][j]==0) f[i][j]=f[f[i][j-1]][j-1];
            if(f[i][j]) ans=j;
        }
    printf("%d\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值