Description:
给出一些串和一个母串,每次可以从母串中删除一个给出串并拼接,问最终最短多少。
Solution:
比较难的
dp
d
p
。
最终目的计算
o[i][j]
o
[
i
]
[
j
]
表示
i−>j
i
−
>
j
是否可以完全消去,然后
dp
d
p
一下就行了。
设一个
dp[i][j][k][l]
d
p
[
i
]
[
j
]
[
k
]
[
l
]
表示
i−>j
i
−
>
j
可以削成第
k
k
<script type="math/tex" id="MathJax-Element-84">k</script>个串的前l位,转移一下就行了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 55;
int n, L;
int ddp[155], len[maxn];
bool dp[155][155][maxn][maxn], o[155][155];
char S[155], s[maxn][maxn];
int main() {
scanf("%s%d", S + 1, &n);
L = strlen(S + 1);
for(int i = 1; i <= n; ++i) {
scanf("%s", s[i] + 1);
len[i] = strlen(s[i] + 1);
}
for(int i = L; i; --i) {
for(int j = i; j <= L; ++j) {
for(int k = 1; k <= n; ++k) {
dp[i][i - 1][k][0] = 1;
for(int l = 1; l <= j - i + 1 && l <= len[k]; ++l) {
dp[i][j][k][l] |= dp[i][j - 1][k][l - 1] && S[j] == s[k][l];
for(int t = i; t < j; ++t) {
dp[i][j][k][l] |= dp[i][t][k][l] && o[t + 1][j];
}
}
}
for(int k = 1; k <= n; ++k) {
if(dp[i][j][k][len[k]]) {
o[i][j] = 1;
break;
}
}
}
}
memset(ddp, 0x3f3f, sizeof(ddp));
ddp[0] = 0;
for(int i = 1; i <= L; ++i) {
ddp[i] = ddp[i - 1] + 1;
for(int j = i; j; --j) {
if(o[j][i]) {
ddp[i] = min(ddp[j - 1], ddp[i]);
}
}
}
printf("%d\n", ddp[L]);
return 0;
}
感想:删东西考虑区间dp。