[luogu] CF607B Zuma

题目详情
题目分析:

  • 这一题跟P4170 [CQOI2007]涂色类似。(附上本博客题解)。
  • f[i][j]表示区间i~j拿走回文序列最少多少次。
  • 状态转移方程:
    • 如果i==j
      f [ i ] [ j ] = 1 ; f[i][j] = 1; f[i][j]=1;
    • 如果i != j 且 s[i] == s[j]:
      f [ i ] [ j ] = f [ i + 1 ] [ j − 1 ] ; f[i][j] = f[i + 1][j - 1]; f[i][j]=f[i+1][j1];
    • 如果i != j 且 s[i] != s[j]:
      f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] ) ( k = 1 , 2 , 3 ⋅ ⋅ ⋅ ) ; f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]) (k = 1, 2, 3···); f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])(k=1,2,3);
  • 在dp时跟P4170 [CQOI2007]涂色有些不一样,要把长度为2的区间单独转移。因为转移方程的 f [ i ] [ j ] = f [ i + 1 ] [ j − 1 ] ; f[i][j] = f[i + 1][j - 1]; f[i][j]=f[i+1][j1];限制了区间长度至少是3。
#include 
#include 
#include 
using namespace std;
int n, f[555][555], s[555];
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", s + i);
    memset(f, 0x3f, sizeof(f));
    for (int i = 1; i <= n; i++)
        f[i][i] = 1;
    for (int i = 1; i < n; i++)
        f[i][i + 1] = 1 + (s[i] != s[i + 1]);
    for (int len = 3; len <= n; len++)
        for (int i = 1, j = len; j <= n; i++, j++)
        {
            if (s[i] == s[j])
                f[i][j] = f[i + 1][j - 1];
            for (int k = i; k < j; k++)
                f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]);
        }
    printf("%d\n", f[1][n]);
}

你可能感兴趣的:(算法)