Codeforces Round #336 (Div. 2) D. Zuma

D - Zuma

题意:给你一个数字组成的串, 每次你能消去一段连续的回文串,问你最少需要操作几次把所有数字删完。

思路:区间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 */

 

posted @ 2018-04-20 00:26  NotNight  阅读(101)  评论(0编辑  收藏  举报