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;
}

 

posted @ 2020-04-04 00:06  kjd123456  阅读(156)  评论(0编辑  收藏  举报