관련 항목
주제 링크
루오 밸리, https://www.luogu.com.cn/problem/P1019 .
총 승객 마늘, https://nanti.jisuanke.com/t/T2110 .
총 승객 마늘, https://nanti.jisuanke.com/t/T2152 .
내 OJ, http://47.110.135.197/problem.php?id=4209 .
제목 설명
카드 놀이 카드 놀이는 우리가 비슷한 게임의 관용구로 재생하는 데 사용되는 단어입니다, 지금 우리가 단어의 집합을 알고, 가장 긴 "드래곤"을 필요로 시작하는 편지를 주어 (각 단어는이 편지로되어 시작 (가)에서의 "긴"대부분에 두번 나타나는 서로 중복 부분의 일부를 만들어, 짐승 놀라게 예컨대, 기차에 접속하는 경우가 beastonish된다 두 단어에 접속 될 때), 두 개의 추가 부분을 인접 관계에있어서 존재할 수 없다 , 예를 들면, atide의 사이에 접속 될 수 없다.
입력 형식
첫 번째 행동 입력 단일 정수 N (n≤20)는 단어의 수를 나타냅니다, 각 단어가 다음 n 줄은 단일 문자의 마지막 행위의 입력은 처음에 문자 "드래곤"을 나타냅니다. 당신이이 문자 "용"로 시작된다고 가정 할 수 있어야합니다.
출력 형식
그냥 출력의 길이는이 편지 가장 긴 "드래곤"로 시작합니다.
SAMPLE INPUT
5
at
touch
cheat
choose
tact
a
샘플 출력
23
설명
가장 긴 용은 atoucheatactactouchoose입니다.
주제 분석
문제의 의미 분석
단어 주어진 시점에서 가장 긴 용을 찾을 수 있습니다. 각 단어는 드래곤에 두 번 최대에 표시합니다.
예를 들어, 전술의 샘플 데이터를이 단어는 단지 첫 글자와 마지막 글자는 카드 놀이의 규칙에 따라, 당신의 자신을 취할 수, t되어있다.
샘플 데이터 분석
아래와 같이 우리의 샘플 데이터에 따르면, 상기 관계가 그려 질 수있다 :
가장 긴 단어를 찾기 위해, 위와 같이, DFS는 가능한 모든 DFS에 쓰기로 처음부터 발견 할 수있는 가장 긴 자연적인 과정이다. 만나 DFS 탐색의 요구 사항은 다음을 찾을 수 있습니다 :
22 atoucheatoucheatactact
17 atoucheatouchoose
22 atoucheatactoucheatact
20 atoucheatactouchoose
22 atoucheatactactoucheat
23 atoucheatactactouchoose
10 atouchoose
22 atactoucheatoucheatact
20 atactoucheatouchoose
22 atactoucheatactoucheat
23 atactoucheatactouchoose
13 atactouchoose
22 atactactoucheatoucheat
23 atactactoucheatouchoose
16 atactactouchoose
로 (23)의 최대 길이 이상을 알 수있다.
알고리즘의 생각
1, 판독 데이터.
2, 리더를 찾고.
3, 구조적 변화 관계형 데이터.
4 수도꼭지 모든 통해, 현재 DFS와 수도꼭지, DFS는, 모든 가능한 얻을 가장 긴 데이터를 찾을 수 있습니다.
어떻게 단어 카드 놀이 할 수 있습니다 결정?
필요 최소 오버랩 길이를 찾을 수 있습니다. 카드 놀이 및 다른 워드 abababab은, 우연의 일치 문자, 즉 단어 AB, 카드 놀이는 ababababababab이며,이해야 abababab 예를 들어, 단어가되게합니다.
폭력의 각각의 비교
이 문제는 작은 데이터 량 ≤ N (20)으로 인해, 폭력의 사용과 비교하는 것이 가능하다. 즉, 각각의 비교 문자열 다음 놀이, 즉이 기능을 달성 할 수있는 캐릭터 (B)의 k 번째 위치 :
bool check(const string &a, const string &b, int k)
세대 테이블
관계형 테이블을 유지한다. 위의 그림으로, 우리는 테이블을 생성하는 사용자의 데이터를 읽습니다. 이것은 몇 문자 일치 접속 나중에 설명 문자열 문자열 B를 표현하는 2 차원 배열을 설명한다 고려한다. 이러한 샘플의 입력으로도 지시를 참조하면, 우리는 다음의 표에 도시 된 관계를 구 초기화 문제가없는 두 단어 맞추기는 0이고, 고려할 수 있으며, x> 0이 반복 후행 접속 j 번째 단어에서 i 번째 단어를 나타낸다 X 자.
워드 | ...에서 | 접촉 | 사기 | 고르다 | 재치 |
...에서 | 0 | 1 | 0 | 0 | 1 |
접촉 | 0 | 0 | 이 | 이 | 0 |
사기 | 0 | 1 | 0 | 0 | 1 |
고르다 | 0 | 0 | 0 | 0 | 0 |
재치 | 0 | 1 | 0 | 0 | 1 |
무슨 아직 테이블에 의미합니까? A [I] [J]를 몇 j 번째 문자열 일치 뒤에 접속 i 번째 문자열을 나타낸다. 이러한 [1] [2] = 2, 스트링 터치 속이 연결 문자열 반복 문자 놀이 toucheat의 단어의 길이. 5 (접촉 길이) + 5 (치트 길이의 끝을 나타낸다 ) - 2- (오버랩 길이) = 8.
코드 구현 아이디어
1 TT으로 표시되는 최소 워드 길이에서, i 번째와 j 번째의 단어를 얻었다.
도 2에서, I, J == 경우, 워드, 다음 저장 TT 설명한다. 그들이 할 수 없기 때문에
3, 개방 루프, 시작부터 종료까지 K 1 TT. 동일한 문자 K는, 애프터 연결된 단어 나 한 경우 K 캐릭터의 정면에서 촬영 한 i 번째의 단어의 j 번째 단어 K 문자 전면 뒤로 찍은 J를 번째 긴 단어가있을 것이다 K 문자가 반복됩니다.
4주기의 종료 후, 무엇을 포함 관계를 결정한다. 계산 TT 문자와 동일한 크기를 반복하는 경우, 상기 관계를 설명.
다음과 같이 코드가 실행된다 :
//找龙头和构建重复字符表
vector<int> head;
for (int i=0; i<n; i++) {
if (ch==word[i].at(0)) {
head.push_back(i);
}
//第i个单词后面接上第j个单词,将重复 k 个字符
for (int j=0; j<n; j++) {
int tt = min(word[i].length(), word[j].length());
string tmp1, tmp2;
for (int k=1; k<=tt; k++) {
//word[i]逆序获取
tmp1 = word[i].substr(word[i].length()-k, k);
//word[j]正序获取
tmp2 = word[j].substr(0, k);
if (tmp1==tmp2) {
relation[i][j]=k;
break;
}
}
//包含关系
if (relation[i][j]==tt) {
relation[i][j]=0;
}
}
}
AC 참조 코드
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int MAXN = 20+2;
const int MAXUSED = 2;
string word[MAXN];//单词
int used[MAXN];//单词已经使用次数
int relation[MAXN][MAXN];
int sum;//当前龙单词长度
int ans;//最长的长度
int n;//
string dragon;
//用第 i 个单词开始接龙
void dfs(int i) {
//标志位,如果发生遍历说明数据构造没有结束
bool flag = true;
//遍历
for (int j=0; j<n; j++) {
//第 j 个单词没有超过使用限制
//并且第 j 个单词可以接着第 i 个单词后面
if (used[j]<MAXUSED && relation[i][j]>0) {
used[j]++;
sum += (word[j].length()-relation[i][j]);
dragon += word[j].substr(relation[i][j], word[j].length()-relation[i][j]);
dfs(j);
sum -= (word[j].length()-relation[i][j]);
used[j]--;
dragon = dragon.substr(0, dragon.length()-(word[j].length()-relation[i][j]));
flag = false;
}
}
if (true == flag) {
//cout << dragon << " " << sum << endl;
ans = max(ans, sum);
}
}
int main() {
cin >> n;
for (int i=0; i<n; i++) {
cin>>word[i];
}
char ch;
cin >> ch;
//找龙头和构建重复字符表
vector<int> head;
for (int i=0; i<n; i++) {
if (ch==word[i].at(0)) {
head.push_back(i);
}
//第i个单词后面接上第j个单词,将重复 k 个字符
for (int j=0; j<n; j++) {
int tt = min(word[i].length(), word[j].length());
string tmp1, tmp2;
for (int k=1; k<=tt; k++) {
//word[i]逆序获取
tmp1 = word[i].substr(word[i].length()-k, k);
//word[j]正序获取
tmp2 = word[j].substr(0, k);
if (tmp1==tmp2) {
relation[i][j]=k;
break;
}
}
//包含关系
if (relation[i][j]==tt) {
relation[i][j]=0;
}
}
}
int index;
vector<int>::iterator it;
for (it=head.begin(); it<head.end(); it++) {
index = *it;
used[index]++;
sum += word[index].length();
dragon = word[index];
dfs(index);
sum -= word[index].length();
used[index]--;
}
cout << ans << endl;
return 0;
}
추신
글 설명은 너무 피곤 TMD이 보고서를 앞뒤로, 지속적으로 수정 알고리즘 사고 부분의 4+ 시간을 썼다보고한다. 문제에 대한 해결책은 분석의 대상이 가장 중요하는 문제의 해결에보고하지만, 코드를 볼 수 없습니다.