二叉树后的习题
文章目录
05-树7 堆中的路径(分数25)
题目要求
将一系列给定数字依次插入一个初始为空的小顶堆H[]。随后对任意给定的下标i,打印从H[i]到根结点的路径。
输入格式
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输出格式
对输入中给出的每个下标i,在一行中输出从H[i]到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。
输入样例:
5 3
46 23 26 24 10
5 4 3
输出样例:
24 23 10
46 23 10
26 10
代码
#include <iostream>
#define MinH -10001
using namespace std;
int s = 0; //记录堆的当前容量
void Insert(int H[], int data);
void PrintH(int H[], int index);
int main(){
int n, m, data;
cin >> n;
cin >> m;
int H[n + 1];
H[0] = MinH;
for(int i = 1; i < n + 1; i++){
cin >> data;
Insert(H, data);
}
//进行打印输出
int index;//用于存放要打印的根节点的序号
for(int j = 0; j < m; j++){
cin >> index;
PrintH(H, index);
if( j != m - 1) cout << endl;
}
return 0;
}
void Insert(int H[], int data){
int i;
//从最末尾的元素开hi向上比较
for(i = ++s; H[i / 2] > data ; i /= 2) H[i] = H[i / 2];
H[i] = data;
}
void PrintH(int H[], int index){
for(int i = index; i > 0; i /= 2){
cout << H[i];
if( i != 1) cout << " ";
}
}
05-树8 File Transfer(分数 25)
题目要求
We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?
Input Specification:
Each input file contains one test case. For each test case, the first line contains N (2 ≤ N ≤ 104), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.
I c1 c2
where I stands for inputting a connection between c1 and c2; or
C c1 c2
where C stands for checking if it is possible to transfer files between c1 and c2; or
S
Onput Specification:
For each C case, print in one line the word “yes” or “no” if it is possible or impossible to transfer files between c1 and c2, respectively. At the end of each case, print in one line “The network is connected.” if there is a path between any pair of computers; or “There are k components.” where k is the number of connected components in this network.
Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
Sample Onput 1:
no
no
yes
There are 2 components.
Sample Input 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
Sample Onput 2:
no
no
yes
yes
The network is connected.
代码
#include<iostream>
using namespace std;
#define MaxSize 10000
typedef int SetType[MaxSize];
void Initial_connections(SetType s, int n);
void Input_connections(SetType s);
void Check_connections(SetType s);
void Check_network(SetType s, int n);
int Find(SetType s, int x);
void Union(SetType s, int root1, int root2);
int main(){
int n;
cin >> n;
char input;
SetType s;
Initial_connections(s, n);
do{
cin >> input;
switch( input ){
case 'I': Input_connections(s); break;
case 'C': Check_connections(s); break;
case 'S': Check_network(s, n); break;
}
} while( input != 'S');
return 0;
}
//进行初始化
void Initial_connections(SetType s, int n){
for(int i = 0; i < n; i++){
s[i] = -1;//进行初始化
}
}
// 连接两个元素不在一个集合则进行合并
void Input_connections(SetType s){
int x1, x2;
cin >> x1;
cin >> x2;
int root1, root2;
root1 = Find(s, x1 - 1);
root2 = Find(s, x2 - 1);
if( root1 != root2 )
Union(s, root1, root2);
}
//检查两个元素是否在一个集合中
void Check_connections(SetType s){
int x1, x2;
cin >> x1;
cin >> x2;
int root1, root2;
root1 = Find(s, x1 - 1);
root2 = Find(s, x2 - 1);
if( root1 == root2 ) cout << "yes" << endl;
else cout << "no" << endl;
}
//检查整个网络中有几个连通域,只有一个元素的集合也算一个单独的连通域
void Check_network(SetType s, int n){
int counter = 0;
for(int i = 0; i < n; i++){
if(s[i] < 0) ++counter;
}
if(counter == 1) cout << "The network is connected." << endl;
//一开始犯低级错误:components后面没加句号“.”
else cout << "There are " << counter << " components." << endl;
}
//查找给定元素的根节点,并在此处进行路径压缩
int Find(SetType s, int x){
if(s[x] < 0){
return x;
}
//递归逻辑:(路径压缩)最初的输入X到集合根结点路径上的结点,把这些结点的父结点都设为根结点
else
return s[x] = Find(s, s[x]);
}
//连接两个元素,即将两个集合进行合并,按秩归并,此处是按规模大小合并
//如果要用路径压缩,则根据规模大小按秩归并比按树的高度更加方便
void Union(SetType s, int root1, int root2){
if( s[root1] < s[root2] ){ //把规模小的挂在规模大的上面
s[root1] += s[root2];
s[root2] = root1;
}
else{
s[root2] += s[root1];
s[root1] = root2;
}
}
05-树9 Huffman Codes(分数 30)
题目要求
In 1953, David A. Huffman published his paper “A Method for the Construction of Minimum-Redundancy Codes”, and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string “aaaxuaxz”, we can observe that the frequencies of the characters ‘a’, ‘x’, ‘u’ and ‘z’ are 4, 2, 1 and 1, respectively. We may either encode the symbols as {‘a’=0, ‘x’=10, ‘u’=110, ‘z’=111}, or in another way as {‘a’=1, ‘x’=01, ‘u’=001, ‘z’=000}, both compress the string into 14 bits. Another set of code can be given as {‘a’=0, ‘x’=11, ‘u’=100, ‘z’=101}, but {‘a’=0, ‘x’=01, ‘u’=011, ‘z’=001} is NOT correct since “aaaxuaxz” and “aazuaxax” can both be decoded from the code 00001011001001. The students are submitting all kinds of codes, and I need a computer program to help me determine which ones are correct and which ones are not.
Input Specification:
Each input file contains one test case. For each case, the first line gives an integer N (2≤N≤63), then followed by a line that contains all the N distinct characters and their frequencies in the following format:
c[1] f[1] c[2] f[2] ... c[N] f[N]
where c[i] is a character chosen from {‘0’ - ‘9’, ‘a’ - ‘z’, ‘A’ - ‘Z’, ‘_’}, and f[i] is the frequency of c[i] and is an integer no more than 1000. The next line gives a positive integer M (≤1000), then followed by M student submissions. Each student submission consists of N lines, each in the format:
c[i] code[i]
where c[i] is the i-th character and code[i] is an non-empty string of no more than 63 '0’s and '1’s.
Output Specification:
For each test case, print in each line either “Yes” if the student’s submission is correct, or “No” if not.
Note: The optimal solution is not necessarily generated by Huffman algorithm. Any prefix code with code length being optimal is considered correct.
Sample Input:
7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11
Sample Onput:
Yes
Yes
No
No
代码
#include <iostream>
#include <string.h>
using namespace std;
#define MaxSize 64
//哈夫曼树的数据结构
typedef struct TNode *HuffmanTree;
struct TNode{
int weight;
HuffmanTree Left;
HuffmanTree Right;
};
//最小堆的数据结构,里面存着结点的数组
typedef struct HeapNode *MinHeap;
struct HeapNode{
HuffmanTree ht[MaxSize];
int Size;
};
MinHeap CreateMinHeap();//初始化最小堆
HuffmanTree CreateHuffmanTree();//初始化哈夫曼树
void Insert(MinHeap h, HuffmanTree ht);//构造最小堆
HuffmanTree BuildHuffmanTree(MinHeap h);//构造哈夫曼树
HuffmanTree DeleteMin(MinHeap h);//删除最小堆中的最小结点
int ComputeWPL(HuffmanTree root, int depth);//计算哈夫曼树的WPL
int Judge(int n, int WPL, char ch[], int w[]);//从两方面进行判断
int main(){
int n;
cin >> n;
//首先初始化、创建最小堆
MinHeap h;
h = CreateMinHeap();
HuffmanTree ht, root;
char ch[MaxSize];
int w[MaxSize];
for(int i = 0; i < n; i++){
cin >> ch[i];
cin >> w[i];
ht = CreateHuffmanTree();
ht -> weight = w[i];
Insert(h, ht);
}
root = BuildHuffmanTree(h);
int WPL = ComputeWPL(root, 0);
int m;
cin >> m;
int flag = 1;
for(int j = 0; j < m; j++){
flag = Judge(n, WPL, ch, w);
if(flag) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
MinHeap CreateMinHeap(){
MinHeap h;
h = (MinHeap)malloc(sizeof(struct HeapNode));
h -> ht[0] = (HuffmanTree)malloc(sizeof(struct TNode));
h -> ht[0] -> weight = -1;
h -> ht[0] -> Left = NULL;
h -> ht[0] -> Right = NULL;
h -> Size = 0;
return h;
}
HuffmanTree CreateHuffmanTree(){
HuffmanTree ht;
ht = (HuffmanTree)malloc(sizeof(struct TNode));
ht -> weight = 0;
ht -> Left = NULL;
ht -> Right = NULL;
return ht;
}
void Insert(MinHeap h, HuffmanTree x){
int i = ++h->Size;
while(h -> ht[i / 2] -> weight > x -> weight){
h -> ht[i] = h -> ht[i / 2];
i /= 2;
}
h -> ht[i] = x;
}
HuffmanTree BuildHuffmanTree(MinHeap h){
HuffmanTree t;
int num = h -> Size;
//注意此处,从i = 1出开始插入,因为i = 0处一般不用
for(int i = 1; i < num; i++){
t = CreateHuffmanTree();
t -> Left = DeleteMin(h);
t -> Right = DeleteMin(h);
t -> weight = t -> Left -> weight + t -> Right -> weight;
Insert(h, t);
}
t = DeleteMin(h);
return t;
}
HuffmanTree DeleteMin(MinHeap h){
int Parent, Child;
HuffmanTree tmp, MinTmp;
MinTmp = h -> ht[1];
tmp = h -> ht[h->Size--];
for(Parent = 1; Parent * 2 <= h -> Size; Parent = Child){
Child = Parent * 2;
if((Child != h -> Size) && (h -> ht[Child] -> weight > h -> ht[Child + 1] -> weight))
Child++;
if(tmp -> weight <= h -> ht[Child] -> weight) break;
else h -> ht[Parent] = h -> ht[Child];
//疑问:这里直接令父亲结点 = 儿子结点,为什么不是直接将权重调换
//这么调换不会破坏最小堆吗
//不会,因为Parent的左右指向的结点是换了,但是最小堆的数组顺序没换
//但为什么不能直接调换权重
}
h -> ht[Parent] = tmp;
return MinTmp;
}
int ComputeWPL(HuffmanTree root, int depth){
if((root -> Left == NULL) && (root -> Right == NULL)){
return depth * root -> weight;
}
else{
return ComputeWPL(root -> Left, depth + 1) + ComputeWPL(root -> Right, depth + 1);
}
}
/*判定法则:
1、最小路径是否和哈夫曼树相等
2、判断是否为前缀码,即所有字母所在的结点是否为叶子结点。
*/
int Judge(int n, int WPL, char ch[], int w[]){
int flag = 1, weight, lenth = 0;
int index;
char c, *s;
s = (char *)malloc(sizeof(char) * MaxSize);
HuffmanTree ht, tmp;
tmp = CreateHuffmanTree();
//注意!!!这当中的循环,就算已经判定了flag = 0也不能break,要继续执行
//因为要保证输入的顺序是正确的
for(int i = 0; i < n; i++){
cin >> c;
cin >> s;
if(strlen(s) >= n){
flag = 0;
}
else{
for(index = 0; c != ch[index]; index++);
weight = w[i];
ht = tmp;
for(int j = 0; j < strlen(s); j++){
if(s[j] == '0'){
if(ht -> Left == NULL) ht -> Left = CreateHuffmanTree();
ht = ht -> Left;
}
else if(s[j] == '1'){
if(ht -> Right == NULL) ht -> Right = CreateHuffmanTree();
ht = ht -> Right;
}
//有weight说明此处已经有字母
//前缀码判定1:判定是否经过了别的字母
if(ht -> weight) flag = 0;//此处不能break,要将本行的数据继续扫描完。
}
if(ht -> Left || ht -> Right) flag = 0;//前缀码判定2:判定是否为叶子结点
else ht -> weight = weight;
}
lenth += strlen(s) * ht -> weight;
}
if( WPL != lenth) flag = 0;//判定路径长度是否和WPL相等
return flag;
}
06-图1 列出连通集(分数25)
题目要求
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式
输入第 1 行给出 2 个整数 N (0 < N ≤ 10) 和 E ,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式
按照"{ v1 v2 … vk}"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。
输入样例:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
代码
//这个代码用的是C++写的
#include <iostream>
#include <queue>
using namespace std;
#define MaxN 10
typedef int Vertex;
int Nv, Ne;
int G[MaxN][MaxN] = {0};
int Visited[MaxN] = {0};
queue<Vertex> q;//用于进行广度优先搜索
/*深度优先搜索*/
void PrintConnectedDFS();
void DFS(Vertex V);
/*广度优先搜索*/
void PrintConnectedBFS();
void BFS(Vertex V);
int main(){
/*读数据*/
cin >> Nv;
cin >> Ne;
Vertex V1, V2;
for(int e = 0; e < Ne; e++){
cin >> V1;
cin >> V2;
G[V1][V2] = 1;
G[V2][V1] = 1;
}
PrintConnectedDFS();
for(int i = 0; i < MaxN; i++) Visited[i] = 0;
PrintConnectedBFS();
}
void PrintConnectedDFS(){
Vertex V;
for(V = 0; V < Nv; V++){
if( !Visited[V] ){
cout << "{ ";
DFS(V);
cout << "}" << endl;
}
}
}
void DFS(Vertex V){
cout << V << " ";
Visited[V] = 1;
for(Vertex W = 0; W < Nv; W++){
if(G[V][W] == 1 && !Visited[W]) DFS(W);
}
}
void PrintConnectedBFS(){
Vertex V;
for(V = 0; V < Nv; V++){
if( !Visited[V] ){
cout << "{ ";
BFS(V);
cout << "}" << endl;
}
}
}
void BFS(Vertex V){
cout << V << " ";
q.push(V);
Visited[V] = 1;
while(!q.empty()){
/*front函数只是返回队列的第一个元素,但并没有将其弹出。pop函数是只做弹出,不能返回值,即不能直接写成V = q.pop(),必须得分成下面两步写。*/
V = q.front();
q.pop();
for(Vertex W = 0; W < Nv; W++){
if(G[V][W] == 1 && !Visited[W]){
cout << W << " ";
Visited[W] = 1;
q.push(W);
}
}
}
}
06-图2 Saving James Bond - Easy Version(分数 25)
题目要求
This time let us consider the situation in the movie “Live and Let Die” in which James Bond, the world’s most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape – he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head… Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).
Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.
Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.
Output Specification:
For each test case, print in a line “Yes” if James can escape, or “No” if not.
Sample Input 1:
14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20
-13 29
-30 15
-35 40
12 12
Sample Onput 1:
Yes
Sample Input 2:
4 13
-12 12
12 12
-12 -12
12 -12
Sample Onput 2:
No
代码
#include <iostream>
#include <cmath>
using namespace std;
#define MaxN 100
typedef int Vertex;
int N, D;
/*将N个鳄鱼当成图的结点*/
/*边用于表示N个鳄鱼间的关系,若是0,则表示鳄鱼间距离太宽跳不过*/
int G[MaxN][MaxN] = {0};
/*用于表示第i只鳄鱼是否被踩过*/
int Visited[MaxN] = {0};
/*x和y分别表示第i只鳄鱼在100 * 100的图里的坐标在哪,
用于判断能否通过该鳄鱼跳上岸*/
int x[MaxN] = {0};
int y[MaxN] = {0};
void save007();
int DFS(Vertex V);
double distance(int x1, int x2, int x3, int x4);/*计算鳄鱼间的距离*/
int IsSafe(Vertex V);/*判断能否踩着鳄鱼V上岸*/
int main(){
cin >> N;
cin >> D;
for(int v = 0; v < N; v++){
cin >> x[v] >> y[v];
}
for(int i = 0; i < N; i++){
for(int j = i + 1; j < N; j++){
double dis = distance(x[i],x[j],y[i],y[j]);
if(dis < D || dis == D){
G[i][j] = 1;/*表示i和j鳄鱼可以跳跃*/
G[j][i] = 1;
}
}
}
save007();
}
void save007(){
int answer = 0;
for(int V = 0; V < N; V++){
double dis = distance(x[V],0,y[V],0);
if( !Visited[V] && !(dis > D + 15 )){
answer = DFS(V);
if(answer) break;
}
}
if(answer) cout << "Yes";
else cout << "No";
}
int DFS( Vertex V ){
int answer = 0;
Visited[V] = true;
if(IsSafe(V)) answer = 1;
else{
for(int W = 0; W < N; W++){
if(G[V][W] && !Visited[W]){
answer = DFS(W);
if(answer == 1) break;
}
}
}
return answer;
}
double distance(int x1, int x2, int y1, int y2){
double dis, dis2;
dis2 = pow(x1 - x2, 2) + pow(y1 - y2, 2);
dis = pow(dis2, 0.5);
return dis;
}
int IsSafe(Vertex V){
int answer = 0;
int dx,dy;
dx = x[V] > 0 ? x[V] : -x[V];
dy = y[V] > 0 ? y[V] : -y[V];
if(dx > (50 - D) || dx == (50 - D) || dy > (50 - D) || dy == (50 - D))
answer = 1;
return answer;
}
06-图3 六度空间(分数30)
题目要求
“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图1所示。
“六度空间”理论虽然得到广泛的认同,并且正在得到越来越多的应用。但是数十年来,试图验证这个理论始终是许多社会学家努力追求的目标。然而由于历史的原因,这样的研究具有太大的局限性和困难。随着当代人的联络主要依赖于电话、短信、微信以及因特网上即时通信等工具,能够体现社交网络关系的一手数据已经逐渐使得“六度空间”理论的验证成为可能。
假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。
输入格式
输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤103,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。
输出格式
对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。
输入样例:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
输出样例:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%
伪代码(思路)
/*算法思路:
对每个节点,进行BFS;
搜索过程中累计访问的节点数;
需要记录“层数”,仅计算6层以内的节点数。*/
int BFS ( Vertex V ) {
visited[V] = true;
count = 1;
level = 0;
last = V;/*当前层的最后一个结点*/
Enqueue(V, Q);
while(!IsEmpty(Q)){
V = Dequeue(Q);
for ( V 的每个邻接点 W )
if ( !visited[W] ) {
visited[W] = true;
Enqueue(W, Q); count++;
tail = W;/*该循环结束后,tail存储的就是V的下一层最后的一个结点处了*/
}
if ( V == last ) {//当弹出的V为当层的最后一个结点时,即表示该层结束,层数++,last就存储下一层的最后一个结点了
level++;
last = tail;
}
if ( level == 6 ) break;
}
return count;
代码
注意点: 输出的小数点格式要注意。还有存放数据的队列,如果不是在函数体内定义的队列,记得每循环一次要清空一下。
cout输出的数字格式参考链接: 写的挺详细的
#include <iostream>
#include <queue>
#include <bits/stdc++.h>//用于控制小数点输出位数
using namespace std;
#define MaxN 1001
int G[MaxN][MaxN] = {0};
int Visited[MaxN] = {0};
typedef int Vertex;
int N,M;
int BFS(Vertex V);
int main(){
cin >> N >> M;
int V1,V2;
for(int edge = 0; edge < M; edge++){
cin >> V1 >> V2;
G[V1][V2] = 1;
G[V2][V1] = 1;
}
for(int V = 1; V < N + 1; V++){
int count = 0;
count = BFS(V);
cout << V <<": ";
cout << setiosflags(ios::fixed) << setprecision(2) << (count * 100.00)/N <<"%"<<endl;
/*或者用以下输出,记得count和N要转换为double类型,否则d算出来不对
double d = 100 * double(count)/double(N);
cout << setiosflags(ios::fixed) << setprecision(2) << d <<"%"<<endl;*/
for(int i = 1; i < N + 1; i++) Visited[i] = 0;
}
return 0;
}
int BFS(Vertex V){
queue<int> q;
Visited[V] = 1;
int count = 1;
int level = 0;
Vertex last = V, tail = V;
q.push(V);
while( !q.empty() ){
V = q.front();
q.pop();
for(int W = 1; W < N + 1; W++){
if(G[V][W] && !Visited[W]){
//cout << "V = " << V << " ";
//cout << "W = " << W << endl;
Visited[W] = 1;
q.push(W);
count++;
tail = W;
}
}
if( V == last ){
level++;
last = tail;
}
if( level == 6) break;
/*极易错误点!此处如果level = 6后,队列中可能不是空的,所以要记得清空队列*/
}
return count;
}