1337:【例3-2】单词查找树
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 1810 通过数: 954
【题目描述】
在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里。为了提高查找和定位的速度,通常都画出与单词列表所对应的单词查找树,其特点如下:
1.根结点不包含字母,除根结点外每一个结点都仅包含一个大写英文字母;
2.从根结点到某一结点,路径上经过的字母依次连起来所构成的字母序列,称为该结点对应的单词。单词列表中的每个单词,都是该单词查找树某个结点所对应的单词;
3.在满足上述条件下,该单词查找树的结点数最少。
4.例如图3-2左边的单词列表就对应于右边的单词查找树。注意,对一个确定的单词列表,请统计对应的单词查找树的结点数(包含根结点)。
【输入】
为一个单词列表,每一行仅包含一个单词和一个换行/回车符。每个单词仅由大写的英文字母组成,长度不超过63个字母 。文件总长度不超过32K,至少有一行数据。
【输出】
仅包含一个整数,该整数为单词列表对应的单词查找树的结点数。
【输入样例】
A
AN
ASP
AS
ASC
ASCII
BAS
BASIC
【输出样例】
13
思路:
首先一波百度:
字典树
又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
学习博客:https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html
大致过程是:每个节点代表一个字母,每插入一个单词时,进行一次插入处理。
每个节点都有A-Z共26个孩子,存到节点对应child数组[0-25]
从单词的第1个字母开始遍历:当当前节点对应该字母的child数组为空,给他创建一下,节点数+1
cnt表示前缀出现的次数。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
struct node{
int cnt;
node *child[27];
};
int ans;
node *build(){
node *k=new node;
k->cnt=0;
memset(k->child,0,sizeof(k->child));
return k;
}
void Insert(node *root,char *s){
while(*s){
int id=*s-'A';
if(root->child[id]==NULL){
root->child[id]=build();
ans++;
}
root=root->child[id];
root->cnt++;
s++;
}
}
int main(){
char s[100];
node *q=build();
while(scanf("%s",s)!=EOF){
Insert(q,s);
}
printf("%d\n",++ans);
}
1338:【例3-3】医院设置
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 1067 通过数: 756
【题目描述】
设有一棵二叉树(如图3-8,其中圈中的数字表示结点中居民的人口,圈边上数字表示结点编号。现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻结点之间的距离为1。就本图而言,若医院建在1处,则距离和=4+12+2*20+2*40=136;若医院建在3处,则距离和=4*2+13+20+40=81……
【输入】
第一行一个整数n,表示树的结点数(n≤100)。接下来的n行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为0表示无链接;第三个数为右链接,为0表示无链接。
【输出】
一个整数,表示最小距离和。
【输入样例】
5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
【输出样例】
81
思路
写了个dfs……
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=115,mod=32767;
int tmp,cnt,a[N],head[N];
struct A{
int to,nex;
}edge[2*N];
void add(int from,int to){
edge[cnt].to=to;
edge[cnt].nex=head[from];
head[from]=cnt++;
}
void dfs(int now,int dep,int pre){
tmp+=a[now]*dep;
for(int i=head[now];i!=-1;i=edge[i].nex){
int dot=edge[i].to;
if(dot==pre)continue;
dfs(dot,dep+1,now);
}
}
int main(){
int n,x,y;
scanf("%d",&n);
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
scanf("%d%d",&x,&y);
if(x!=0){add(i,x);add(x,i);}
if(y!=0){add(i,y);add(y,i);}
}
int ans=INF;
for(int i=1;i<=n;i++){
tmp=0;
dfs(i,0,0);
ans=min(ans,tmp);
}
printf("%d\n",ans);
}
1340:【例3-5】扩展二叉树
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 905 通过数: 693
【题目描述】
由于先序、中序和后序序列中的任一个都不能唯一确定一棵二叉树,所以对二叉树做如下处理,将二叉树的空结点用·补齐,如图所示。我们把这样处理后的二叉树称为原二叉树的扩展二叉树,扩展二叉树的先序和后序序列能唯一确定其二叉树。
现给出扩展二叉树的先序序列,要求输出其中序和后序序列。
【输入】
扩展二叉树的先序序列。
【输出】
输出其中序和后序序列。
【输入样例】
ABD..EF..G..C..
【输出样例】
DBFEGAC
DFGEBCA
思路:
注意对于扩展二叉树,边读边建树,对于建树的过程,不会结束不了,因为叶子节点的左右子树肯定是空的,输入的最后一个字符肯定是 '.' 这时候就返回NULL
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
char s[N];
struct node{
struct node *lc,*rc;
char elem;
};
node *Create_tree(){
char ch;
scanf("%c",&ch);
if(ch=='.')return NULL;
node *q=new node;
q->elem=ch;
q->lc=Create_tree();
q->rc=Create_tree();
return q;
}
void Post_print(node *q){
if(q!=NULL){
Post_print(q->lc);
Post_print(q->rc);
printf("%c",q->elem);
}
}
void In_print(node *q){
if(q!=NULL){
In_print(q->lc);
printf("%c",q->elem);
In_print(q->rc);
}
}
int main(){
node *q=Create_tree();
In_print(q);
printf("\n");
Post_print(q);
printf("\n");
}
1364:二叉树遍历(flist) - 中序,层次推先序
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 860 通过数: 552
【题目描述】
树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。
假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。
【输入】
两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的中序遍历和按层遍历的序列。
【输出】
一行,表示二叉树的先序序列。
【输入样例】
DBEAC
ABCDE
【输出样例】
ABDEC
思路:
每次都要遍历一遍层次遍历的数组,把已经输出的数组用vis标记为1
对于每一个子树,我们用一个范围表示它在中序遍历里的数组下标范围。
然后遍历层序遍历的数组,找到数组里出现的第一个(第一个是根)满足没被输出并且,出现在中序遍历数字的范围里。
这个值作为子树的根。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=200015,mod=32767;
int vis[N];
char s1[N],s2[N];
void solve(int now,int len1,int len2){
int i,j;
for(i=0;i<len2;i++){//从层序遍历里找根节点
if(vis[i])continue;
for(j=now;j<len1;j++){
if(s1[j]==s2[i]){
printf("%c",s2[i]);
vis[i]=1;
break;
}
}
if(vis[i])break;
}
if(j>now)solve(now,j,len2);
if(j+1<len1)solve(j+1,len1,len2);
}
int main(){
scanf("%s%s",s1,s2);
solve(0,strlen(s1),strlen(s2));
printf("\n");
}
1366:二叉树输出(btout)
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 714 通过数: 393
【题目描述】
树的凹入表示法主要用于树的屏幕或打印输出,其表示的基本思想是兄弟间等长,一个结点的长度要不小于其子结点的长度。二叉树也可以这样表示,假设叶结点的长度为1,一个非叶结点的长度等于它的左右子树的长度之和。
一棵二叉树的一个结点用一个字母表示(无重复),输出时从根结点开始:
每行输出若干个结点字符(相同字符的个数等于该结点长度),
如果该结点有左子树就递归输出左子树;
如果该结点有右子树就递归输出右子树。
假定一棵二叉树一个结点用一个字符描述,现在给出先序和中序遍历的字符串,用树的凹入表示法输出该二叉树。
【输入】
两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的先序遍历和中序遍历的序列。
【输出】
行数等于该树的结点数,每行的字母相同。
【输入样例】
ABCDEFG
CBDAFEG
【输出样例】
AAAA
BB
C
D
EE
F
G
思路:
知识简单的记录一下节点“长度”
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
struct node{
node *lc,*rc;
char elem;
int dep;
};
char s1[N],s2[N];
node *solve(char *pre,char *in,int len){
if(len==0)return NULL;
int k=0;
for(;k<len;k++){
if(in[k]==*pre)break;
}
node *q=new node;
q->elem=*pre;
q->lc=solve(pre+1,in,k);
q->rc=solve(pre+k+1,in+k+1,len-k-1);
if(q->rc==NULL&&q->lc==NULL)q->dep=1;
else if(q->lc==NULL)q->dep=q->rc->dep;
else if(q->rc==NULL)q->dep=q->lc->dep;
else q->dep=q->lc->dep+q->rc->dep;
return q;
}
void pre_print(node *q){
if(q==NULL)return ;
for(int i=1;i<=q->dep;i++){
printf("%c",q->elem);
}
printf("\n");
pre_print(q->lc);
pre_print(q->rc);
}
int main(){
scanf("%s%s",s1,s2);
node *q=solve(s1,s2,strlen(s2));
pre_print(q);
}