题意:
相同的两个x可以合并成x+1,给一个序列,问最后最少能剩下多少个元素。n (1≤n≤500)
题解:
看了别人的题解后自己的理解。
dp[i][j]表示i到j区间合并后的最小个数,合并左右两个区间前提是两个区间dp值为1并且元素相等。
简单的证明:分割点为w,左区间最优合并后剩下 2、5 ,右区间最优合并后剩下5,
在w之前,i到w'合并后为2,w’到end两个五合并后为6,这时已经和分割点为w合并的情况一样了。
a[i][j]为合并后剩的元素,初始化为-1,只有区间i,j剩的元素个数为1时,a[i][j]!=-1.
状态转移方程
if(dp[j][w]==1&&dp[w+1][end]==1&&a[j][w]==a[w+1][end])
dp[j][end]=1,a[j][end]=a[j][w]+1;
dp[j][end]=min(dp[j][w]+dp[w+1][end],dp[j][end]);
代码:
#include<bits/stdc++.h> #define endl '\n' using namespace std; typedef long long ll; typedef double db; typedef pair<int,int> pii; typedef vector<int> vi; #define check system("pause") #define all(x) (x).begin(),(x).end() #define de(a) cout<<#a<<" = "<<a<<endl #define dd(a) cout<<#a<<" = "<<a<<" " #define mp make_pair #define pb push_back #define fi first #define se second #define lowbit(a) ((a)&-(a)) #define INF 0x3f3f3f3f const ll mod = 1e9+7; const int N = 1e6+20; #define dep(i,a,b) for(int i=(a);i>=(b);i--) #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define mes(p,b) memset(p,b,sizeof(p)) #define sz(x) int(x.size()) int a[501][501],dp[501][501]; int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int n; cin>>n; mes(a,-1); mes(dp,0x3f); rep(i,1,n){ cin>>a[i][i]; dp[i][i]=1; } rep(len,2,n) for(int j=1;j+len-1<=n;j++){ int end=j+len-1; rep(w,j,end-1){ dp[j][end]=min(dp[j][w]+dp[w+1][end],dp[j][end]); if(dp[j][w]==1&&dp[w+1][end]==1&&a[j][w]==a[w+1][end]) dp[j][end]=1,a[j][end]=a[j][w]+1; } } cout<<dp[1][n]; return 0; }