Fun Game
https://odzkskevi.qnssl.com/8d698323a1e07d605cdeea708ee8a01d?v=1508703139
【题解】
不难发现如果一个串的原串或反转串是另一个串的子串,那么这个串是没有用的
我们把他剔除出去
如果此时只有一个串,暴力枚举解检查即可(网上很多写法是KMP。。不是很明白,没仔细看他们代码
多个串则状压DP
dp[s][i][0/1]表示s串已经选了,最后一个串是i,i是正着/倒着的,最大重叠字母数
刷表法转移即可
如何处理圈?我们强行在第一个串的地方断开,按照第一个串的正着的方向为圈的传递方向即可,
最后的时候枚举最后一个串跟第一个串交一下算答案
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <vector> 7 #define min(a, b) ((a) < (b) ? (a) : (b)) 8 #define max(a, b) ((a) > (b) ? (a) : (b)) 9 10 inline void swap(int &a, int &b) 11 { 12 long long tmp = a;a = b;b = tmp; 13 } 14 15 inline void read(int& x) 16 { 17 x = 0;char ch = getchar(), c = ch; 18 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 19 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 20 } 21 22 const int INF = 0x3f3f3f3f; 23 const int MAXN = 20; 24 const int MAXNUM = 1000; 25 26 int dp[(1 << MAXN) + 10][MAXN + 5][2], die[MAXN][2][MAXN][2], n, ma, sum, len[MAXN], cnt[MAXN], tot, b[MAXN]; 27 char s[MAXN][MAXNUM]; 28 29 inline void init() 30 { 31 memset(dp, 0, sizeof(dp)); 32 memset(die, 0, sizeof(die)); 33 tot = 0; 34 sum = 0; 35 memset(b, 0, sizeof(b)); 36 memset(len, 0, sizeof(len)); 37 memset(cnt, 0, sizeof(cnt)); 38 //check j是否包含在i中 39 for(register int i = 1;i <= n;++i) 40 { 41 scanf("%s", s[i] + 1); 42 len[i] = strlen(s[i] + 1); 43 } 44 for(register int i = 1;i <= n;++ i) 45 for(register int j = 1;j <= n;++ j) 46 { 47 if(i == j || b[i] || b[j] || len[j] > len[i])continue; 48 //正着配 49 for(register int a = 1;a <= len[i] - len[j] + 1;++ a) 50 { 51 int tmp1 = a; 52 while(s[i][tmp1] == s[j][tmp1 - a + 1] && tmp1 - a + 1 <= len[j]) ++ tmp1; 53 if(tmp1 - a + 1 > len[j]) b[j] = 1; 54 } 55 //倒着配 56 for(register int a = len[i];a >= len[j];-- a) 57 { 58 int tmp1 = a, p = 1; 59 while(s[i][tmp1] == s[j][p] && p <= len[j]) -- tmp1, ++ p; 60 if(p > len[j]) b[j] = 1; 61 } 62 } 63 for(register int i = 1;i <= n;++ i) 64 if(!b[i]) 65 cnt[++ tot] = i, sum += len[i]; 66 //j跟在i后面重叠部分大小 67 for(register int p = 1;p <= tot;++ p) 68 for(register int q = 1;q <= tot;++ q) 69 { 70 int i = cnt[p], j = cnt[q]; 71 if(i == j)continue; 72 //0 0 73 for(register int a = 1;a <= len[i];++ a) 74 { 75 int b = 1, tmp = a; 76 while(s[i][tmp] == s[j][b] && tmp <= len[i] && b <= len[j])++ tmp, ++ b; 77 if(tmp > len[i]) 78 { 79 die[p][0][q][0] = len[i] - a + 1; 80 break; 81 } 82 } 83 //0 1 84 for(register int a = 1;a <= len[i];++ a) 85 { 86 int b = len[j], tmp = a; 87 while(s[i][tmp] == s[j][b] && tmp <= len[i] && b >= 1)++ tmp, -- b; 88 if(tmp > len[i]) 89 { 90 die[p][0][q][1] = len[i] - a + 1; 91 break; 92 } 93 } 94 //1 0 95 for(register int a = len[i];a >= 1;-- a) 96 { 97 int b = 1, tmp = a; 98 while(s[i][tmp] == s[j][b] && tmp >= 1 && b <= len[j])-- tmp, ++ b; 99 if(tmp < 1) 100 { 101 die[p][1][q][0] = a; 102 break; 103 } 104 } 105 //1 1 106 for(register int a = len[i];a >= 1;-- a) 107 { 108 int b = len[j], tmp = a; 109 while(s[i][tmp] == s[j][b] && tmp >= 1 && b >= 1)-- tmp, -- b; 110 if(tmp < 1) 111 { 112 die[p][1][q][1] = a; 113 break; 114 } 115 } 116 } 117 ma = 1 << tot; 118 } 119 120 int main() 121 { 122 while(scanf("%d", &n) != EOF && n) 123 { 124 init(); 125 int flag = 0; 126 if(tot == 1) 127 { 128 int x = cnt[tot]; 129 for(register int i = 1;i <= len[x];++ i) 130 { 131 for(register int j = 1;j <= len[x];++ j) 132 { 133 if(j + i - 1 > len[x]) break; 134 int p1 = 1, p2 = j, rank = 0; 135 while(s[x][p1] == s[x][p2] && rank < len[x]) 136 { 137 ++ p1, ++ p2, ++ rank; 138 if(p1 > len[x]) p1 = 1; 139 if(p2 > j + i - 1) p2 = 1; 140 } 141 if(rank >= len[x]) 142 { 143 printf("%d\n", max(2, i)); 144 flag = 1; 145 break; 146 } 147 } 148 if(flag) break; 149 } 150 if(flag) continue; 151 } 152 //dp[S][i][0/1]表示以1号字符串为头,已经选了S,最后一个是i的正/反状态的最大折叠数 153 //dp[S | k][k][p] = max(dp[S | k][k][p], dp[S][i][p'] + die[i][p'][k][p]) 154 for(register int S = 0;S < ma;++ S) 155 for(register int i = 1;i <= tot;++ i)/*分别用dp[S][i][0]和dp[S][i][1]去更新*/ 156 { 157 if(!(S & 1))continue; 158 if(!(S & (1 << (i - 1)))) continue; 159 for(register int k = 1;k <= tot;++ k) 160 { 161 if(S & (1 << (k - 1))) continue; 162 if(S == 1) 163 { 164 dp[S | (1 << (k - 1))][k][0] = max(dp[S | (1 << (k - 1))][k][0], dp[S][i][0] + die[i][0][k][0]); 165 dp[S | (1 << (k - 1))][k][1] = max(dp[S | (1 << (k - 1))][k][1], dp[S][i][0] + die[i][0][k][1]); 166 } 167 else 168 { 169 dp[S | (1 << (k - 1))][k][0] = max(dp[S | (1 << (k - 1))][k][0], max(dp[S][i][0] + die[i][0][k][0], dp[S][i][1] + die[i][1][k][0])); 170 dp[S | (1 << (k - 1))][k][1] = max(dp[S | (1 << (k - 1))][k][1], max(dp[S][i][0] + die[i][0][k][1], dp[S][i][1] + die[i][1][k][1])); 171 } 172 } 173 } 174 int ans = 0; 175 for(register int i = 1;i <= tot;++i) 176 ans = max(ans, max(dp[ma - 1][i][0] + die[i][0][1][0], dp[ma - 1][i][1] + die[i][1][1][0])); 177 printf("%d\n", max(2, sum - ans)); 178 } 179 return 0; 180 }