题目描述
Io和Ao在玩一个单词游戏。
他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致。
游戏可以从任何一个单词开始。
任何单词禁止说两遍,游戏中只能使用给定词典中含有的单词。
游戏的复杂度定义为游戏中所使用的单词长度总和。
编写程序,求出使用一本给定的词典来玩这个游戏所能达到的游戏最大可能复杂度。
输入格式
输入文件的第一行,表示一个自然数N(1≤N≤16),N表示一本字典中包含的单词数量以下的每一行包含字典中的一个单词,每一个单词是由字母A、E、I、O和U组成的一个字符串,每个单词的长度将小于等于100,所有的单词是不一样的。
输出格式
输出文件仅有一行,表示该游戏的最大可能复杂度。
输入输出样例
输入 #1复制
5
IOO
IUUO
AI
OIOOI
AOOI
输出 #1复制
16
思路
使用DFS + 最优性剪枝,对于相同首末尾的单词,优先选择较长的单词,跳过其余剩下的较短的单词。
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define MAXN 20
inline int read() {
int x = 0; bool f = 0; char ch = getchar();
while (!isdigit(ch)) f = (ch == 45), ch = getchar();
while ( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f ? (~x + 1) : x;
}
struct word {
char a, b;
int len;
}e[MAXN];
int n, maxn = 0;
int vis[MAXN] = {0}; // 表示该单词是否已访问
bool cmp(word x, word y) {
if (x.a < y.a) return 1;
if (x.a == y.a && x.b < y.b) return 1;
if (x.a == y.a && x.b == y.b && x.len > y.len) return 1;
return 0;
}
void dfs(int s, int dis) {
maxn = max(maxn, dis);
vis[s] = 1;
for (int i = 1; i <= n; i++) {
if (e[s].b == e[i].a && !vis[i]) {
dfs(i, dis + e[i].len);
while (e[i].a == e[i + 1].a && e[i].b == e[i + 1].b) i++;// 最优性剪枝,使得在s点不用搜索除i以外的其他首末尾相同的单词
}
}
vis[s] = 0;
}
int main() {
string s;
n = read();
for (int i = 1; i <= n; i++) {
cin >> s;
e[i].len = s.length();
e[i].a = s[0];
e[i].b = s[e[i].len - 1];
}
sort(e + 1, e + 1 + n, cmp); // 对于相同首末尾的单词,按照长度从大到小排序
for (int i = 1; i <= n; i++) {
dfs(i, e[i].len);
}
cout << maxn << endl;
return 0;
}