题目大意:给一个有$n(nleqslant16)$个单词的字典,求单词接龙的最大长度
题解:发现$n$很小,可以状压,令$f_{i,j}$表示选的数的状态为$i$,最后一个字母是$j$的最大长度。
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #define maxn 16 #define N (1 << maxn | 3) char s[105]; int n, len[maxn], l[maxn], r[maxn]; int f[N][6]; inline int get(char x) { switch (x) { case 'A': return 1; case 'E': return 2; case 'I': return 3; case 'O': return 4; case 'U': return 5; default: return 20040826; } } int q[N], h, t = -1, ans; bool inq[N]; inline int max(int a, int b) {return a < b ? a : b;} inline void getmax(int &a, int b) {if (a < b) a = b;} int main() { scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%s", s); len[i] = strlen(s); l[i] = get(s[0]); r[i] = get(s[len[i] - 1]); f[1 << i][r[i]] = len[i]; getmax(ans, f[1 << i][r[i]]); inq[q[++t] = 1 << i] = true; } while (h <= t) { int u = q[h++]; for (int i = 1; i <= 5; i++) if (f[u][i]) { for (int j = 0; j < n; j++) if (!(u & 1 << j)) { int v = u | 1 << j; if (l[j] == i) { getmax(f[v][r[j]], f[u][i] + len[j]); getmax(ans, f[v][r[j]]); if (!inq[v]) inq[q[++t] = v] = true; } } } } printf("%d ", ans); return 0; }