[SCOI2007]压缩
题目链接:https://www.luogu.com.cn/problem/P2470
题解:
区间DP。设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]代表字母
i
i
i前面有字母‘M’,字符串
[
i
,
j
]
[i,j]
[i,j]子段压缩后的最短长度。
递推式:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
k
]
+
j
−
k
)
(
i
≤
k
<
j
)
dp[i][j] = min(dp[i][j], dp[i][k]+j-k)(i\le k<j)
dp[i][j]=min(dp[i][j],dp[i][k]+j−k)(i≤k<j)
若子段
[
i
,
k
]
[i,k]
[i,k]与子段
[
k
+
1
,
j
]
[k+1,j]
[k+1,j]相等,则有
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
j
−
k
+
1
,
d
p
[
j
]
[
k
]
+
1
)
;
dp[i][j] = min(dp[i][j], j-k+1,dp[j][k]+1);
dp[i][j]=min(dp[i][j],j−k+1,dp[j][k]+1);
求出
d
p
dp
dp数组后,则再简单动规求最短的长度即可。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<ctime>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 120;
const int mod = 19260817;
char str[maxn];
int dp[maxn][maxn];
int main()
{
int n, m, i, j, k;
memset(dp, 0x3f, sizeof(dp));
scanf("%s", str+1);
n = strlen(str+1);
for(i=2;i<=n;i++)
for(j=1;i+j-1<=n;j++){
int r = i+j-1;
for(k=j;k<r;k++){
dp[j][r] = min(dp[j][r], dp[j][k]+r-k);
if(k-j+1 == r-k && strncmp(str+j, str+k+1, r-k)==0){
if(j == 1)dp[j][r] = min(dp[j][r], r-k+1);
else dp[j][r] = min(dp[j][r], r-k+2);
dp[j][r] = min(dp[j][r], dp[j][k]+1);
}
}
}
for(i=1;i<=n;i++)
dp[1][i] = min(dp[1][i], i);
for(i=2;i<=n;i++)
for(j=i+1;j<=n;j++)
dp[1][j] = min(dp[1][j], dp[1][i-1]+dp[i][j]);
printf("%d\n", dp[1][n]);
return 0;
}