题目链接
感觉这个dp还是蛮棒棒的^^
我们让
f[i][j][a][b]=0/1
f
[
i
]
[
j
]
[
a
]
[
b
]
=
0
/
1
表示大串中i~j的子串与第a个小串1~b的字串是否完全相同,
ok[i][j]=0/1
o
k
[
i
]
[
j
]
=
0
/
1
表示大串中i~j的子串能否全部拿空,
dp[i]
d
p
[
i
]
表示大串前i个字符最少剩下几个。
则有状态转移方程
f[i][j][a][b]|=(f[i][j−1][a][b−1] and t[j]==s[a][b])||(f[i][k][a][b] and ok[k+1][j])(k=i..j−1)
f
[
i
]
[
j
]
[
a
]
[
b
]
|
=
(
f
[
i
]
[
j
−
1
]
[
a
]
[
b
−
1
]
a
n
d
t
[
j
]
==
s
[
a
]
[
b
]
)
|
|
(
f
[
i
]
[
k
]
[
a
]
[
b
]
a
n
d
o
k
[
k
+
1
]
[
j
]
)
(
k
=
i
.
.
j
−
1
)
ok[i][j]|=f[i][j][a][len[a]]
o
k
[
i
]
[
j
]
|
=
f
[
i
]
[
j
]
[
a
]
[
l
e
n
[
a
]
]
dp[i]=min(dp[i−1]+1,dp[j] and ok[j+1][i])
d
p
[
i
]
=
m
i
n
(
d
p
[
i
−
1
]
+
1
,
d
p
[
j
]
a
n
d
o
k
[
j
+
1
]
[
i
]
)
观察发现通过状压可以压掉一维的空间复杂度和时间复杂度。于是就可以乱搞了。
非状压代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int lt,n,ls[35],ok[151][151],f[151][151][31][21],dp[151];
char t[155],s[35][25];
int main(){
scanf("%s",t+1);
lt=strlen(t+1);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s[i]+1);
ls[i]=strlen(s[i]+1);
}
for(int i=1;i<=lt;i++){
for(int j=1;j<=n;j++){
if(t[i]==s[j][1]){
f[i][i][j][1]=1;
ok[i][i]|=f[i][i][j][ls[j]];
}
}
}
for(int i=lt;i>=1;i--){
for(int j=i+1;j<=lt;j++){
for(int a=1;a<=n;a++){
for(int b=1;b<=ls[a];b++){
f[i][j][a][b]|=(f[i][j-1][a][b-1]&&t[j]==s[a][b]);
for(int k=i;k<=j-1;k++){
f[i][j][a][b]|=(f[i][k][a][b]&&ok[k+1][j]);
}
}
ok[i][j]|=f[i][j][a][ls[a]];
}
}
}
for(int i=1;i<=lt;i++){
dp[i]=dp[i-1]+1;
for(int j=0;j<i;j++){
if(ok[j+1][i]){
dp[i]=min(dp[i],dp[j]);
}
}
}
printf("%d\n",dp[lt]);
return 0;
}
状压代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int lt,n,bin[35],ls[35],ok[151][151],f[151][151][31],dp[151];
char t[155],s[35][25];
int main(){
scanf("%s",t+1);
lt=strlen(t+1);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s[i]+1);
ls[i]=strlen(s[i]+1);
}
bin[0]=1;
for(int i=1;i<=30;i++){
bin[i]=bin[i-1]<<1;
}
for(int i=1;i<=lt;i++){
for(int j=1;j<=n;j++){
if(t[i]==s[j][1]){
f[i][i][j]|=bin[1];
ok[i][i]|=(f[i][i][j]&bin[ls[j]]);
}
}
}
for(int i=lt;i>=1;i--){
for(int j=i+1;j<=lt;j++){
for(int a=1;a<=n;a++){
for(int b=1;b<=ls[a];b++){
f[i][j][a]|=((f[i][j-1][a]&bin[b-1])&&t[j]==s[a][b])*bin[b];
}
for(int k=i;k<=j-1;k++){
if(ok[k+1][j]){
f[i][j][a]|=f[i][k][a];
}
}
ok[i][j]|=(f[i][j][a]&bin[ls[a]]);
}
}
}
for(int i=1;i<=lt;i++){
dp[i]=dp[i-1]+1;
for(int j=0;j<i;j++){
if(ok[j+1][i]){
dp[i]=min(dp[i],dp[j]);
}
}
}
printf("%d\n",dp[lt]);
return 0;
}