【洛谷】 P3879 [TJOI2010]閱讀理解
0.總結
Get to the points first. The article comes from LawsonAbs!
- trie樹
- 二維數組隱式越界坑
1.題意
判斷一個單詞是否出現在某串文本中。如果出現,則輸出文本的序號【按照從小到大的方式】,否則直接輸出換行。
2.分析
典型的模板題,使用 trie
就可以解決。這裏我不再介紹tried樹了,簡單說一下我的主要解決步驟:
- step 1.使用一個trie 數組用於存儲每串文本的結構。由題意知,可以設計一個三維數組
trie[][][]
,其中第一維表示的是第幾篇閱讀;第二維表示節點個數;第三維表示指向【類同二維的tried數組】 - step 2.依次遍歷每個查詢字符串,然後輸出即可。
3.代碼
// Created by lawson on 20-6-21.
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN = 1005; //表示最大的短文數,同時也作爲最大的個數
const int maxM = 20000;
int n,m;//n表示短文數
short trie[maxN][maxM][27];// 26個小寫字母
int p = 0,cnt = 1,tot = 0;//cnt 表示第幾篇短文;
bool endF[maxN][maxN];//結束標誌 => 用bool省空間
void build(char in[] ){
int p = 0;
for(int i = 0;i<strlen(in);i++){
int cNum = in[i]-'a';
if(!trie[cnt][p][cNum]){//如果沒有記錄
trie[cnt][p][cNum] = ++tot;
}
p = trie[cnt][p][cNum];//更新p的值
}
endF[cnt][p] = true;
}
//查詢in這個字符串是否在trie樹中
bool search(int index,char in[]){
p = 0;
for(int i = 0;i<strlen(in);i++){
int cNum = in[i]-'a';
if(!trie[index][p][cNum])
return false;
else
p = trie[index][p][cNum];
}
if(endF[index][p])
return true;
return false;
}
int main(){
scanf("%d",&n);
while(cnt<=n){
tot = 0;//重置爲0
scanf("%d",&m);
char word[30];//每個字符長20
for(int i = 1;i<=m;i++){
scanf("%s",word);//輸入每個單詞
build(word);
}
cnt++;
}
scanf("%d",&m);
char query[25];//待查詢的字符串
for(int i = 1;i<= m;i++){
int res[maxN];//存儲答案
cnt = 0;//重置
scanf("%s",query);
for(int j = 1;j<=n;j++)
if(search(j,query))
res[cnt++] = j;
//更換輸出格式
for(int j = 0;j<cnt;j++)
if(j!=cnt-1) printf("%d ",res[j]);
else printf("%d",res[j]);
printf("\n");//輸出一個空行
}
}
4.測試用例
2
1 youare
3 my name is
2
you
you
1
3 you you you
1
you
1
4 you a good person
1
yo
3
9 you are a good boy ha ha o yeah
13 o my god you like bleach naruto one piece and so do i
11 but i do not think you will get all the points
5
yo
s
o
all
all
5.坑點
- 需要注意數組大小的申請,一般情況下,很難得到一個**“高維數組的越界提示”**,比如說二維數組
arr[10][10]
,你如果用arr[5][20]
依然是可以訪問到值!所以一定要注意題目的數據範圍大小到底需要一個什麼範圍的數組!千萬別模棱兩可。