题目大意
给定一个长度为n的数组,相邻的两个数字如果相同就可以合并成一个比他们大一的数字,
问:最后可以达到的最短的数组长度为多少
样例
input
5
4 3 2 2 3
output
2
样例解释:
3,4位的2合并成 3 --> 4 3 3 3
2 3号位的合并成4 --> 4 4 3
1 2 号位4合并成5 --> 5 3
答案就是 2
思路
用二维数组将数组在对角线位置存起来
4 0 0 0 0
0 3 0 0 0
0 0 2 0 0
0 0 0 2 0
0 0 0 0 3
通过合并操作就可以得到如下数组
4 0 0 5 0
0 3 0 4 0
0 0 2 3 4
0 0 0 2 0
0 0 0 0 3
转换过程
最后通过cost数组模拟转换过程,如最后的3由左上角的2+1,而2是由cost[0]+1, 因为他的最上面5这个位置不是0, 代表它可以合并3次,就剩她1一个,所以到他为止的长度为1.
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 520;
int n, a[N][N], f[N];
int cost[500], dp[500][500];
int main()
{
scanf("%d", &n);
memset(dp, -1, sizeof dp);
for (int i = 0; i < n; i++)
scanf("%d", &dp[i][i]);
for(int len = 2; len <= n; len++)
{
for(int left = 0; left + len - 1 < n; left++)
{
int right = left + len - 1;
for(int t = left; t < right; t++)
{
if(dp[left][t] == dp[t + 1][right] && dp[left][t] != -1)
dp[left][right] = dp[left][t] + 1;
}
}
}
cost[0] = 0;
for(int i = 1; i <= n; i++)
{
cost[i] = 0x3f3f3f3f;
for(int j = 0; j < i; j++)
{
if(dp[j][i - 1] != -1)
{
cost[i] = min(cost[i], cost[j] + 1);
}
}
}
printf("%d\n", cost[n]);
}