题意:
给定1 ~ n个数,每次可以合并相邻两个相同的数字(数值范围1-40),问最大能合出多少?注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。
数据范围:
2 < = N < = 248 2<=N<=248 2<=N<=248
思路:
和石子合并状态选取的区别:
- 石子合并,相邻的堆合二为一是选取
len
长的区间[l, r]
,每一次的决策点k
是取使dp[i][j]
最大,[l, r]
里的数字是全部参与的, n 堆 的最大值是取dp[1][n]
。 - 可以发现这题的限制,只能是相邻且相同数字合并,(我下意识的就会想到那直接在石子合并里加上判定两个数字等才能合并不就好了么?)那么,如果还是在原来选取选取
len
长的区间[l, r]
状态下,而实际上,[l, r]里的数字全部参与,反而会存在不能合并的情况,比如 2,3,4。所以直接改个状态,区间dp[l, r]
是完全合并得到的最大值,条件是dp[i][k] = dp[k+1][j]
。
状态转移方程:
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + 1 ) [ d p [ i ] [ k ] = = d p [ k + 1 ] [ j ] ] dp[i][j]=max(dp[i][j],dp[i][k]+1) [dp[i][k] == dp[k+1][j]] dp[i][j]=max(dp[i][j],dp[i][k]+1)[dp[i][k]==dp[k+1][j]]
输入:
4
1
1
1
2
输出:
3
#include<bits/stdc++.h>
using namespace std;
const int N = 250;
const int inf=0x3f3f3f3f;
int ans,dp[N][N];
int main()
{
int n,num;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>num;
dp[i][i]=num;
}
for(int len=2;len<=n;len++)
for(int i=1;i<=n-len+1;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
{
if(dp[i][k]==dp[k+1][j])
{
if(dp[i][k]==0) continue; //两个区间不能合并
dp[i][j]=max(dp[i][j],dp[i][k]+1);
ans=max(ans,dp[i][j]); //不能是f[1][n]因为不一定完全合并,ans一定是可以合并里的最大值
}
}
}
cout<<ans<<endl;
return 0;
}