Luogu P1278 单词游戏
最开始还是信仰剪枝函数调用次数设成1e7过的...
后来想了想,优化了一下暴力就过了
爆搜+优化的讲解:
将每个字符串的首字母向尾字母连一条边,边的长度为字符串的长度,答案就是每条边最多只经过一次时,图上的最长路。
看一下以下数据:
4
EAAAAE
EAAAAAE
EAAAAAAAE
EAAAAAAAAAE
如果纯爆搜,需要循环!4 * 4 = 96次,我们可以将这四个字符串“拼”成一个字符串,这样原本的四个单词就变成了一个字符串,时间复杂度就会大大减小。
因此我们只要将首尾一样的字符串拼接在一起,(就是将图上的所有自环合并)就可以愉快的AC啦!
$Code:$
#include <iostream> #include <cstdio> #include <algorithm> #include <string> using namespace std; const int MAXN = 50; int get_num(char cur) {//将字符映射成数字 if(cur == 'A') return 1; if(cur == 'E') return 2; if(cur == 'I') return 3; if(cur == 'O') return 4; if(cur == 'U') return 5; } string s; int n,ans; int head[MAXN],t[MAXN],w[MAXN],nxt[MAXN],cnt; bool vis[MAXN]; void addedge(int u,int v,int wei) { t[++cnt] = v; w[cnt] = wei; nxt[cnt] = head[u]; head[u] = cnt; } void DFS(int u,int sum) { ans = max(ans,sum); for(int i = head[u]; i; i = nxt[i]) { if(vis[i]) continue; vis[i] = true; DFS(t[i],sum + w[i]); vis[i] = false; } return; } int main() { scanf("%d",&n); for(int i = 1; i <= 5; i++) {//给每个点都预先加入一条自环 addedge(i,i,0); } //点i的所有自环都将被合并到预先加入的自环上。 for(int i = 1; i <= n; i++) { cin >> s; int len = s.length(); if(s[0] == s[len - 1]) { w[get_num(s[0])] += len;//将首尾相等的字符串合并(合并自环) } else addedge(get_num(s[0]),get_num(s[len - 1]),len); } for(int i = 1; i <= 5; i++) { DFS(i,0); } cout << ans << endl; return 0; }