一、树
1、概念
根和深度
儿子父亲子树森林
叶子:没有儿子的节点
爸爸:父亲的父亲
2、 两点距离最短时过其公共祖先
3、任意两点之间加一条线变成一个环
4、直径:最远两点的路径
任取点P,搜索到P距离最远的Q,再搜索离Q最远的W,直径为QW(证明)
二、二叉树
1、左右儿子,左右子树,
2、前序遍历:根,左子树,右子树
中序遍历:左,根,右
后序遍历:左,右,根
给两种求第三种
3、满二叉树 2^n-1个节点,最大深度为n
完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
三、并查集
路径压缩
- 测验
- 题目:
2003年4月16日,世界卫生组织根据包括中国内地和香港地区,加拿大、美国在内的11个国家和地区的13个实验室通力合作研究的结果,宣布重症急性呼吸综合征的病因是一种新型的冠状病毒,称为SARS冠状病毒。
Input
很不幸,小明同学昨天晚上被确诊以经感染非典病毒,为此,校医院需要对他隔离治疗并隔离观察与他直接或间接接触者。
可以认为,同一个社团内如果有人感染病毒或可能感染病毒,那么这个社团内所有人都被认为是可能已经感染了病毒,由于时间紧迫,需要尽快找到所有可能携带病毒的同学并隔离,以防止更大范围的病毒扩散,院长请你帮忙编写程序计算需要隔离多少人输入文件包含多组数据。
Output
对于每组测试数据:
第一行为两个整数n和m
其中n是学生的数量,m是学生社团的数量。0 < n <= 30000 , 0 <= m <= 500
每个学生编号是一个0到n-1之间的整数,已知小明同学编号是0
紧随其后的是团体的成员列表,每组一行。
每一行有一个整数k,代表成员数量。之后有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
n = m = 0表示输入结束,不需要处理。对于每组测试数据
Sample Input
输出需要隔离的人数,每组输出占一行100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1
题解:典型并查集
注意:fa【x】要初始化,n,m不要搞混
ac代码:
#define M 30010 using namespace std; int m,n,d,a[M],ans,fa[M],x,y; int finda(int x) { if(x==fa[x]) return x; return fa[x]=finda(fa[x]); } int main() { while(~scanf("%d%d",&m,&n)) { if(m==0&&n==0) break; for(int i=0;i<=m;i++) { fa[i]=i; } ans=0; for(int i=0;i) { scanf("%d",&d); scanf("%d",&a[1]); for(int j=2;j<=d;j++) { scanf("%d",&a[j]); if(finda(a[j])!=finda(a[j-1])) fa[finda(a[j])]=finda(a[j-1]); } } x=finda(0); for(int i=0;i ) { y=finda(i); if(y==x) { ans++; } } printf("%d\n",ans); } return 0; }
2.
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
Input
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
Output
Sample Input
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
Sample Output
3
题解:采用3*n来做,x为一种动物,x+n为x的食物,x+2*n为x的敌人,判断是否成立,不成立,continue,成立,link
注意:数组大小要为3倍,fa【x】初始化要到3*n
ac代码:
1 #include2 #define M 200010 3 using namespace std; 4 int n,m,a,x,y,xx,yy,ans,fa[M]; 5 int finda(int x) 6 { 7 if(x==fa[x]) 8 return x; 9 return fa[x]=finda(fa[x]); 10 } 11 void link(int x,int y) 12 { 13 int xx=finda(x),yy=finda(y); 14 if(xx!=yy) 15 fa[xx]=yy; 16 } 17 int main() 18 { 19 scanf("%d%d",&n,&m); 20 for(int i=0;i<=3*n;i++) 21 { 22 fa[i]=i; 23 } 24 for(int i=1;i<=m;i++) 25 { 26 scanf("%d%d%d",&a,&x,&y); 27 if(x>n || y>n || (a==2 &&x==y)) 28 { 29 ans++; 30 //printf(" %d ",i); 31 continue; 32 } 33 if(a==1) 34 { 35 xx=finda(x); 36 yy=finda(y); 37 if(xx==finda(y+2*n) || yy==finda(x+2*n)) 38 { 39 ans++; 40 //printf(" %d ",i); 41 continue; 42 } 43 fa[xx]=yy; 44 link(x,y); 45 link(x+n,y+n); 46 link(x+2*n,y+2*n); 47 } 48 else if(a==2) 49 { 50 xx=finda(x); 51 yy=finda(y); 52 if(xx==yy ||finda(x+2*n)==yy) 53 { 54 ans++; 55 //printf(" %d ",i); 56 continue; 57 } 58 link(x,y+2*n); 59 link(x+n,y); 60 link(x+2*n,y+n); 61 } 62 } 63 printf("%d\n",ans); 64 return 0; 65 }
3.
This is an example of one of her creations:
D
/ \
/ \
B E
/ \ \
/ \ \
A C G
/
/
F
To record her trees for future generations, she wrote down two strings for each tree: a preorder traversal (root, left subtree, right subtree) and an inorder traversal (left subtree, root, right subtree). For the tree drawn above the preorder traversal is DBACEGF and the inorder traversal is ABCDEFG.
She thought that such a pair of strings would give enough information to reconstruct the tree later (but she never tried it).
Now, years later, looking again at the strings, she realized that reconstructing the trees was indeed possible, but only because she never had used the same letter twice in the same tree.
However, doing the reconstruction by hand, soon turned out to be tedious.
So now she asks you to write a program that does the job for her!
Input
Each test case consists of one line containing two strings preord and inord, representing the preorder traversal and inorder traversal of a binary tree. Both strings consist of unique capital letters. (Thus they are not longer than 26 characters.)
Input is terminated by end of file.
Output
Sample Input
DBACEGF ABCDEFG BCAD CBAD
Sample Output
ACBFGED CDAB
题解:给出前序遍历,中序遍历求后序遍历
注意:字符串的输入不加&,判断数组边界
ac代码:
1 #include2 #include 3 #define M 50 4 using namespace std; 5 char a[M],b[M]; 6 int la,lb; 7 void build(int l1,int r1,int l2,int r2) 8 { 9 if(l1>r1) return ; 10 char root=a[l1]; 11 int q=l2,cnt=0; 12 if(l2<r2) 13 { 14 while(b[q++]!=root && q<=r2) cnt++; 15 build(l1+1,l1+cnt,l2,l2+cnt-1); 16 build(l1+cnt+1,r1,l2+1+cnt,r2); 17 } 18 printf("%c",root); 19 } 20 int main() 21 { 22 while(~scanf("%s%s",a+1,b+1)) 23 { 24 la=strlen(a+1); 25 lb=strlen(b+1); 26 build(1,la,1,lb); 27 printf("\n"); 28 } 29 return 0; 30 }
4.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
InputThe input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
OutputFor each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
Sample Input
2 5 3 1 2 2 3 4 5 5 1 2 5
Sample Output
2 4
题解:并查集
ac代码
1 #include2 #define M 1010 3 using namespace std; 4 int t,n,fa[M],vis[M],ans,x,y,m; 5 6 int finda(int x) 7 { 8 if(x==fa[x]) 9 { 10 //printf("fa%d\n",fa[x]); 11 return x; 12 } 13 return fa[x]=finda(fa[x]); 14 } 15 int main() 16 { 17 scanf("%d",&t); 18 while(t--) 19 { 20 scanf("%d%d",&n,&m); 21 for(int i=1;i<=n;i++) 22 { 23 fa[i]=i; 24 vis[i]=0; 25 } 26 for(int i=1;i<=m;i++) 27 { 28 scanf("%d%d",&x,&y); 29 if(finda(x)!=finda(y)) 30 fa[finda(x)]=finda(y); 31 } 32 ans=0; 33 for(int i=1;i<=n;i++) 34 { 35 if(vis[finda(i)]==0) 36 { 37 ans++; 38 // printf("find%d ",finda(i)); 39 vis[finda(i)]++; 40 } 41 } 42 printf("%d\n",ans); 43 } 44 return 0; 45 }
5.
There is exactly one node, called the root, to which no directed edges point.
Every node except the root has exactly one edge pointing to it.
There is a unique sequence of directed edges from the root to each node.
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.
In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not.
6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1Sample Output
Case 1 is a tree. Case 2 is a tree. Case 3 is not a tree.
题解:看出度和入度,(考试的时候没写出来,考完也没改出来),看环,重复,0 0
ac代码
6.
Input
Output
Sample Input
7 6 1 6 13 E 6 3 9 E 3 5 7 S 4 1 3 N 2 4 20 W 4 7 2 S
题解:可dfs,bfs,dp(dp还不会),建立图,add,edge
ac代码
1 #include2 #include 3 #include 4 #define M 1000000 5 using namespace std; 6 int n,m,u,v,w,ans,p,q[M],cnt=1,head[M],vis[M],dis[M],fa[M],s; 7 struct hhh 8 { 9 int to,nxt,w; 10 }edge[M]; 11 void add(int u,int v,int w) 12 { 13 edge[cnt].to=v; 14 edge[cnt].w=w; 15 edge[cnt].nxt=head[u]; 16 head[u]=cnt++; 17 } 18 void dfs(int x) 19 { 20 for(int i=head[x];i;i=edge[i].nxt) 21 { 22 int r=edge[i].to; 23 if(fa[x]==r) 24 continue; 25 fa[r]=x; 26 dis[r]=dis[x]+edge[i].w; 27 dfs(r); 28 } 29 } 30 int main() 31 { 32 scanf("%d%d",&n,&m); 33 memset(head,0,sizeof(head)); 34 for(int i=0;i<=n;i++) fa[i]=i; 35 for(int i=1;i<=m;i++) 36 { 37 scanf("%d%d%d",&u,&v,&w); 38 add(u,v,w); 39 add(v,u,w); 40 getchar(); 41 getchar(); 42 } 43 dfs(1); 44 for(int i=0;i<=n;i++) 45 { 46 if(dis[i]>ans) 47 { 48 ans=dis[i]; 49 p=i; 50 } 51 dis[i]=0; 52 fa[i]=i; 53 } 54 55 printf("\n%d\n%d",p,ans); 56 dfs(p); 57 ans=0; 58 for(int i=0;i<=n;i++) 59 { 60 if(dis[i]>ans) 61 ans=dis[i]; 62 } 63 printf("%d\n",ans); 64 return 0; 65 }
7.
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
Input
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Sample Input
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
Sample Output
1 0 2
题解:用祖先的子序列大小-所求值的深度,深度在finda()中更新
ac代码:
1 #include2 #include 3 #define N 31000 4 using namespace std; 5 int n,s[N],d[N],x,y,fa[N],xx,yy; 6 char a; 7 int finda(int x) 8 { 9 if(x==fa[x]) 10 return x; 11 int tmp=fa[x]; 12 fa[x]=finda(fa[x]); 13 d[x]+=d[tmp]; 14 return fa[x]; 15 } 16 int main() 17 { 18 scanf("%d",&n); 19 // memset(s,1,sizeof(s)); 20 memset(d,0,sizeof(d)); 21 for(int i=1;i ) 22 { 23 fa[i]=i; 24 s[i]=1; 25 d[i]=0; 26 } 27 for(int i=1;i<=n;i++) 28 { 29 scanf(" %c",&a); 30 if(a=='M') 31 { 32 scanf("%d%d",&x,&y); 33 xx=finda(x); 34 yy=finda(y); 35 if(xx!=yy) 36 { 37 fa[yy]=xx; 38 d[yy]=s[xx]; 39 s[xx]+=s[yy]; 40 } 41 42 } 43 if(a=='C') 44 { 45 scanf("%d",&x); 46 printf("%d\n",s[finda(x)]-d[x]-1); 47 } 48 //getchar(); 49 } 50 return 0; 51 }