题意:给你一个数字组成的串, 每次你能消去一段连续的回文串,问你最少需要操作几次把所有数字删完。
思路:区间dp, dp[ i ][ j ]表示删 i 到 j 段最少需要几次。
我们只考虑最左边的那个点的删除情况。
首先dp[ i ] [ j ] <= dp[ i + 1] [ j ] + 1
然后我们枚举 i 到 j 里面的点, 找到a[ k ] == a[ i ]
那么可以得到方程 dp[ i ] [ j ] = min (dp[ i ] [ j ] , dp[ i + 1] [ k - 1] + dp[ k + 1 ] [ j ]), 因为对于a[ i ], a[ k ] 来说肯定能合到dp[ i + 1] [ k - 1]里面消去。
对于a[ i ] == a[ j ] 的情况, dp[ i ] [ j ] = min(dp[ i ] [ j ], dp[ i + 1] [ j - 1] )
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define fi first 4 #define se second 5 #define mk make_pair 6 #define pii pair<int,int> 7 #define ull unsigned long long 8 using namespace std; 9 10 const int N=500+7; 11 const int M=100+7; 12 const int inf=0x3f3f3f3f; 13 const LL INF=0x3f3f3f3f3f3f3f3f; 14 const int mod=1e9 + 9; 15 16 int n, a[N], f[N][N]; 17 18 int dp(int i, int j) { 19 if(i > j) return 1; 20 if(i == j) return 1; 21 if(i + 1 == j) { 22 if(a[i] == a[j]) return 1; 23 else return 2; 24 } 25 if(f[i][j] != -1) return f[i][j]; 26 f[i][j] = dp(i + 1, j) + 1; 27 if(a[i] == a[j]) { 28 f[i][j] = min(f[i][j], dp(i + 1, j - 1)); 29 } 30 for(int k = i + 1; k < j; k++) { 31 if(a[k] == a[i]) { 32 f[i][j] = min(f[i][j], dp(i + 1, k - 1) + dp(k + 1, j)); 33 } 34 } 35 return f[i][j]; 36 } 37 int main() { 38 memset(f, -1, sizeof(f)); 39 scanf("%d", &n); 40 for(int i = 1; i <= n; i++) { 41 scanf("%d", &a[i]); 42 } 43 int ans = dp(1, n); 44 printf("%d\n", ans); 45 return 0; 46 } 47 /* 48 6 49 1 1 1 1 1 1 50 */
原文地址:https://www.cnblogs.com/CJLHY/p/8887494.html
时间: 2024-11-08 20:52:13