洛谷P3146 [USACO16OPEN]248 G----区间dp

题目连接
https://www.luogu.com.cn/problem/P3146

分析:
1.
首先大家都玩过2048这个游戏吧(没玩过也没关系,游戏规则很简单),这道题是1维的2048,两个相邻数字可以合并当且仅当两个数字相同,但是这里合并后的数字不是翻倍而是+1,比如1,2,2第二和第三个数字2可以合并,合并之后为1,3.
2.规则明白之后,接下来开始分析,由于我们求的是能通过合并得到的最大数字,但是我们知道两个不同数字是无法合并的,那么怎样让它们可以合并并且不影响答案呢,我们不妨让这些不能合并的数字合并得到一个极小的值,这样就不会对答案造成影响了,比如1,2这两个数本来是不能合并的,我们这里合并它给它一个极小的数-1000000000(越小越好),那么这样既不会对最大值造成影响也不会影响我们合并区间,那么现在关键步骤来了(也是比较抽象的),我们知道一个区间有很多种合并方式,比如[1,1,2]这个区间,我们可以先合并1,1得到2,那么此时区间变为了[2,2],再合并2,2得到3,此时区间就变为了3,但是如果我们先合并1,2得到-100000000,此时区间变成了[1,-1000000000]再合并1,-100000000得到-1000000000,最终得到一个极小数,我们知道一个极小数对于后面的合并都是无意义的,因为极小数和任何数合并都只会是极小数(就算和它本身合并+1,也要合并1000000000次才能超过0,还没有这个初始的区间最大值大,因为初始区间的数范围也在1-40),所以我们不妨用贪心的策略去合并区间,使得这个区间最后得到一个最大的值,然后我们通过不断合并的过程去实时跟新最大值,例如现在给你一个区间[1,1,2],刚开始最大值Max为2,我们通过贪心最优合并能得到最终数字3,那么这个3就是我们区间合并的结果,而不是-1000000000,那么此时Max就跟新为了3,最后输出Max即可.

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int Maxn = 300;
int f[Maxn][Maxn];
int Max = 0;
int main()
{
	memset(f,~0x7f7f7f7f,sizeof(f));//全部初始化最小值 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>f[i][i];
		Max = max(Max,f[i][i]);//自己和自己合并就是它本身 
	}
    for(int len=1;len<=n;len++)
     for(int i=1;i+len-1<=n;i++)
      for(int j=i;j<i+len-1;j++)
      {
      	int k = i+len-1;
      	/*这两个区间f[i][j]和f[j+1][k]能否合并为一个非极小数,
		  也就是这个两个区间的数是否相等,若不能合并为一个非极小数,
		  那么就不合并,默认f[i][j]为极小数不做处理,因为之前
		  以及初始化了所有f数组的值为极小数~0x7f7f7f7f*/
      	  if(f[i][j]==f[j+1][k])
      	  {
      	  	f[i][k] = max(f[i][k],f[i][j]+1);//合并 
			Max = max(Max,f[i][k]); //实时根新最大值Max 
		  }
		   
	  }
	  printf("%d",Max);
	  return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值