Description:
给出一些串和一个母串,每次可以从母串中删除一个给出串并拼接,问最终最短多少。
Solution:
比较难的dpdp。
最终目的计算o[i][j]o[i][j]表示i−>ji−>j是否可以完全消去,然后dpdp一下就行了。
设一个dp[i][j][k][l]dp[i][j][k][l]表示i−>ji−>j可以削成第kk个串的前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。