求用一个串的四个子串能覆盖原串的最大和最小长度。
比赛的时候没有出这一题,其实思路上差不多都是对的,但细节上没有实现好。。
三维的字符串DP,首先处理出每个子串能够开始的位置,这个暴力一下就行。然后用d[i][j][k]表示长度为i状态为j从当前位置开始已经有k个字符被覆盖的最小长度,j是个四位的二进制状态,为1代表已经使用了这个串。当前位置可以选择使用或者不使用新的未使用子串,DP的时候采用刷表会好写的多。
最小和最大的求法是一样的,开两个数组会爆空间。。改用short就行了。。其实写个函数也挺方便的。。
1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define MAXN 5000 5 #define MAXM 70 6 using namespace std; 7 char s[MAXN], ss[MAXM]; 8 short lens[4], len, maxl; 9 short flag[MAXN], d1[MAXN][16][65], d2[MAXN][16][65]; 10 int main() { 11 while (scanf("%s", s) != EOF) { 12 len = strlen(s); 13 memset(flag, 0, sizeof(flag[0])*len); 14 for (int i = 0; i < 4; i++) { 15 scanf("%s", ss); 16 lens[i] = strlen(ss); 17 for (int j = 0, k; j+lens[i] <= len; j++) { 18 for (k = 0; ss[k]; k++) if (s[j+k] != ss[k]) break; 19 if(ss[k] == '\0') flag[j] |= 1<<i; 20 } 21 if (lens[i] > maxl) maxl = lens[i]; 22 } 23 memset(d1, 0x3f, sizeof(d1[0])*(len+1)); 24 memset(d2, 0xc3, sizeof(d1[0])*(len+1)); 25 d1[0][0][0]=d2[0][0][0]=0; 26 for (int i = 0; i < len; i++) { 27 for (int j = 0; j < 16 ;j++) { 28 for (int k = 0; k <= maxl; k++) { 29 d1[i+1][j][k?k-1:0] = min(d1[i][j][k], d1[i+1][j][k?k-1:0]); 30 d2[i+1][j][k?k-1:0] = max(d2[i][j][k], d2[i+1][j][k?k-1:0]); 31 for (int x = 0; x < 4; x++) { 32 if ((1<<x&~j) && (1<<x&flag[i])) { 33 short t = max((short)k, lens[x]); 34 d1[i][1<<x|j][t] = min((short)(d1[i][j][k]+t-k), d1[i][1<<x|j][t]); 35 d2[i][1<<x|j][t] = max((short)(d2[i][j][k]+t-k), d2[i][1<<x|j][t]); 36 } 37 } 38 } 39 } 40 } 41 printf("%hd %hd\n", d1[len][15][0], d2[len][15][0]); 42 } 43 return 0; 44 }