[SCOI2007]压缩 区间dp

时间:2023-12-03 12:39:32

明显是个区间dp,但是我区间dp就是个渣。。。

f[i][j]表示区间i到j最短的字符长度;假设前面加了个M,所以初始化f[i][i]=2;当然最开始是不算M的,所以f[1][1]=1;然后就可以区间dp了。        f[i][j]=min{f[i][j-1]+1};//从上一个加一更新过来(如果不存在重合的话)

if(a[i]==a[j]&&check(i,j))//判断是否有重合部分

f[i][j+j-i-1]=min(f[i][j+j-i-1],f[i][j-1]+1);//重合部分用R代替,所以要+1.注意好下标,最后再用一个dp合并就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
char a[100],b[100];
int n;
int f[100][100];
int check(int i,int j)
{
    pos(k,1,j-i-1)
    {
       if(a[i+k]!=a[j+k])
        return 0;
    }
    return 1;
}
int main()
{
    memset(f,50,sizeof(f));
    scanf("%s",&b);
    n=strlen(b);
    pos(i,1,n)
      a[i]=b[i-1];
    //cout<<n;

    pos(i,1,n)
      f[i][i]=2;
    f[1][1]=1;
    pos(i,1,n)
      pos(j,i+1,n)
      {
         f[i][j]=min(f[i][j-1]+1,f[i][j]);
         if(a[i]==a[j]&&check(i,j))
           f[i][j+j-i-1]=min(f[i][j+j-i-1],f[i][j-1]+1);
      }
    pos(i,1,n)
      pos(j,i+1,n)
        pos(k,i,j-1)
          f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
    cout<<f[1][n];
    //while(1);
    return 0;
}