浙江大学计算机与软件学院2019年保研上机模拟练习 --- 凌宸1642
浙江大学计算机与软件学院2019年保研上机模拟练习 — 凌宸1642
7-1 Happy Numbers (20 分) — 简单数学
A happy number is defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits in base-ten, and repeat the process until the number either equals 1 (where it will stay), or it loops endlessly in a cycle that does not include 1. Those numbers for which this process ends in 1 are happy numbers and the number of iterations is called the degree of happiness, while those that do not end in 1 are unhappy numbers (or sad numbers). (Quoted from Wikipedia)
For example, 19 is happy since we obtain 82 after the first iteration, 68 after the second iteration, 100 after the third iteration, and finally 1. Hence the degree of happiness of 19 is 4.
On the other hand, 29 is sad since we obtain 85, 89, 145, 42, 20, 4, 16, 37, 58, and back to 89, then fall into an endless loop. In this case, 89 is the first loop number for 29.
Now your job is to tell if any given number is happy or not.
译:一个快乐的数字由以下过程定义:从任何正整数开始,用其以十为底的数字的平方和替换该数字,并重复该过程,直到该数字等于 1(它将停留在哪个位置),或者它在一个不包含 1 的循环中无限循环。这个过程以 1 结束的那些数字是快乐的数字,迭代的次数称为快乐度,而那些不以 1 结尾的则是不快乐的数字(或悲伤的数字)。 (引自*)
例如,19 是快乐的,因为我们在第一次迭代后获得 82,第二次迭代后获得 68,第三次迭代后获得 100,最后为 1。因此 19 的快乐度为 4。 另一方面,29 是悲伤的,因为我们得到 85、89、145、42、20、4、16、37、58,然后回到 89,然后陷入无限循环。 在这种情况下,89 是 29 的第一个循环编号。
现在你的工作是判断任何给定的数字是否快乐
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤100). Then N lines follow, each contains a positive integer (no more than104) to be tested.
译:每个输入文件包含一个测试用例,对于每种情况,第一行给定一个正整数 N (≤100) , 接下来 N 行每行包含一个用于测试的不超过 104 的整数。
Output Specification:
For each given number, output in a line its degree of happiness if it is happy, or the first loop number if it is sad.
译:对于每个给定的数字,如果他是一个开心数的话,在一行中打印它的幸福度,否则,打印第一个开始循环的数。
Sample Input:
3
19
29
1
Sample Output:
4
89
0
The Code:
#include<bits/stdc++.h>
using namespace std ;
int n , ans , t ;
int getSum(int x){ // 得到 x 的数位和
int res = 0 , t ;
while(x){
t = x % 10 ;
res += t * t ;
x /= 10 ;
}
return res ;
}
int main(){
cin >> n ;
for(int i = 0 ; i < n ; i ++){
cin >> t ;
ans = 0 ;
if(t == 1) { // 对输入进行特判是否为 1
cout << 0 << endl ;
continue ;
}
unordered_map<int , bool> mp ; // 用 unordered_map ,标记出该数是否出现
bool status = false ; // 循环的标识
do{
mp[t] = true ;
t = getSum(t) ;
ans ++ ;
if(t == 1) break ; // 满足题意,直接退出循环
if(mp[t]) status = true ; // t 之前出现过,所以此时t是第一个开始循环的数,修改循环标记
}while(!status) ;
if(t == 1) cout << ans << endl ; // 输出开心度
else cout << t << endl ; // 输出第一个进入循环的数
}
return 0 ;
}
7-2 Zigzag Sequence (25 分) — 简单模拟
This time your job is to output a sequence of N positive integers in a zigzag format with width M in non-decreasing order. A zigzag format is to fill in the first row with M numbers from left to right, then the second row from right to left, and so on and so forth. For example, a zigzag format with width 5 for numbers 1 to 13 is the following:
1 2 3 4 5
10 9 8 7 6
11 12 13
译:这次你的工作是输出一个由 N 个正整数组成的锯齿形格式,宽度为 M 的非递减顺序。 锯齿形格式是第一行从左到右填M个数字,第二行从右到左,依此类推。 例如,数字 1 到 13 的宽度为 5 的锯齿形格式如下:
1 2 3 4 5
10 9 8 7 6
11 12 13
Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers N and M. Then the next line contains N positive integers as the original sequence. All the numbers are no more than 104. The numbers in a line are separated by spaces.
译:每个输入文件包含一个测试用例。 对于每种情况,第一行给出 2 个正整数 N 和 M。然后下一行包含 N 个正整数作为原始序列。 所有数字不超过104。一行中的数字用空格分隔。
Output Specification:
For each test case, output the sequence in the zigzag format with width M in non-decreasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the beginning or the end of each line.
译:对于每个测试用例,以非递减顺序输出宽度为 M 的锯齿形格式的序列。 两个相邻数字之间必须正好有 1 个空格,并且每行的开头或结尾都没有多余的空格。
Sample Input 1:
14 5
37 76 98 20 98 76 42 53 99 95 60 81 58 93
Sample Output 1:
20 37 42 53 58
93 81 76 76 60
95 98 98 99
Sample Input 2:
15 4
96 37 76 98 20 98 76 42 53 99 95 60 81 58 93
Sample Output 2:
20 37 42 53
76 76 60 58
81 93 95 96
99 98 98
坑点:
测试点1:当总行数是偶数的时候,最后一行也是需要反序输出的。
The Code :
#include<bits/stdc++.h>
using namespace std ;
int n , m ;
vector<int> num ;
int main(){
cin >> n >> m ;
num.resize(n) ;
for(int i = 0 ; i < n ; i ++) cin >> num[i] ;
sort(num.begin() , num.end()) ; // 将数据从小到大排列
int col = n / m ; // 计算有多少行是满的
for(int i = 0 ; i < col ; i ++){
if(i % 2){ // 将偶数行(索引就为奇数)
reverse(num.begin() + i * m , num.begin() + (i + 1) * m) ;
}
}
if(col % 2) reverse(num.begin() + col * m , num.end()) ;// 如果最后一行的索引为奇数,则逆转
for(int i = 0 ; i < col ; i ++){ // 输出前面的满行
int t = i * m ;
cout << num[t] ;
for(int j = 1 ; j < m ; j ++){
cout << ' ' << num[t + j] ;
}
cout << endl ;
}
for(int i = col * m ; i < n ; i ++){ // 输出最后一行剩余的数字
printf("%d%c" , num[i] , (i == n - 1)?'\n':' ') ;
}
return 0 ;
}
7-3 Is It An AVL Tree (25 分) — AVL 性质
In computer science, an AVL tree (Georgy Adelson-Velsky and Evgenii Landis’ tree, named after the inventors) is a self-balancing binary search tree. It was the first such data structure to be invented. In an AVL tree, the heights of the two child subtrees of any node differ by at most one. (Quoted from wikipedia)
For each given binary search tree, you are supposed to tell if it is an AVL tree.
译:在计算机科学中,AVL 树(Georgy Adelson-Velsky 和 Evgenii Landis 的树,以发明者的名字命名)是一种自平衡二叉搜索树。 这是第一个被发明的数据结构。 在 AVL 树中,任何节点的两个子子树的高度最多相差 1。 (引自*) 对于每个给定的二叉搜索树,您应该判断它是否是 AVL 树。
Input Specification:
Each input file contains several test cases. The first line gives a positive integer K (≤10) which is the total number of cases. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary search tree. The second line gives the preorder traversal sequence of the tree with all the keys being distinct. All the numbers in a line are separated by a space.
译:每个输入文件包含几个测试用例。 第一行给出一个正整数 K (≤10),它是案例总数。 对于每种情况,第一行给出一个正整数 N(≤30),即二叉搜索树中节点的总数。 第二行给出了所有键都不同的树的前序遍历序列。 一行中的所有数字都用空格分隔。
Output Specification:
For each test case, print in a line “Yes” if the given tree is an AVL tree, or “No” if not.
译:对于每个测试用例,如果给定的树是 AVL 树,则在一行中打印“是”,如果不是,则打印“否”。
Sample Input:
3
7
50 40 36 48 46 62 77
8
50 40 36 48 46 62 77 88
6
50 40 36 48 46 62
Sample Output:
Yes
No
No
The Code :
/*
1. 结点较少,可以选择链式结构存储二叉树
2. 建树算法,给出的是 BST ,可以选择插入建树,这里我选择的建树算法是 中序 + 先序 重建二叉树
3. 一颗 AVL 树的条件:左子树右子树都是 AVL 树,且左子树和右子树的高度之差的绝对值小于等于 1
4. 知道如何求解一颗二叉树的高度
*/
#include<bits/stdc++.h>
using namespace std ;
struct node{ // 采用链式结构,存储二叉树
int val ;
node* l;
node* r ;
};
int n , k ;
vector<int> pre , in ;
node* bulid(int preL , int preR , int inL , int inR){ // 中序 + 先序 重建二叉树
if(preL > preR) return NULL ;
node* root = new node() ;
root->val = pre[preL] ;
int t = inL ;
while(in[t] != pre[preL]) t ++ ;
int numLeft = t - inL ;
root->l = bulid(preL + 1 , preL + numLeft , inL , t - 1) ;
root->r = bulid(preL + numLeft + 1 , preR , t + 1 , inR) ;
return root ;
}
// 计算一颗二叉树的高度
int depth(node* root){
if(!root) return 0 ;
int left = depth(root->l) ;
int right = depth(root->r) ;
return max(left , right) + 1 ;
}
bool isAVL(node* root){ // 判断一棵树是否为 AVL
if(!root) return true ;
bool isL = false , isR = false ;
isL = isAVL(root->l) ;
isR = isAVL(root->r) ;
int left = depth(root->l) ;
int right = depth(root->r) ;
return (abs(left - right) < 2) && isL && isR ; // 左右子树均为AVL,并且左右子树高度差小于2
}
int main(){
cin >> k ;
for(int i = 0 ; i < k ; i ++){
cin >> n ;
pre.clear() ;
in.clear() ;
pre.resize(n) , in.resize(n) ;
for(int i = 0 ; i < n ; i ++){
cin >> pre[i] ;
in[i] = pre[i] ;
}
sort(in.begin() , in.end()) ; // 排序之后,得到中序序列 (BST 性质)
node *root = bulid(0 , n - 1 , 0 , n - 1) ;
if(isAVL(root)) cout << "Yes" << endl;
else cout << "No" << endl ;
}
}
7-4 Index of Popularity (30 分) — 无向图的子图的度最大的三个顶点
The index of popularity (IP) of someone in his/her circle of friends is defined to be the number of friends he/she has in that circle. Now you are supposed to list the members in any given friend circle with top 3 IP’s.
译:某人在他/她的朋友圈中的流行指数(IP)定义为他/她在该圈子中的朋友数量。 现在你应该列出任何给定朋友圈中的成员,其中包含前 3 个 IP。
Input Specification:
Each input file contains one test case. Each case starts with a line containing 2 positive integers N and M (both no more than 105), which are the total number of people and the number of friend relations, respectively. Hence the people here are numbered from 1 to N.
Then M lines follow, each contains the indices of a pair of friends, separated by a space. It is assumed that if A is a friend of B, then B is a friend of A.
Then several queries follow, each occupies a line. For each line of query, K (3≤K≤N), the total number of members in this friend circle is given first, with K indices of members follow. It is guaranteed that all the indices in a circle are distinct.
The input ends when K is zero, and this case must NOT be processed.
译:每个输入文件包含一个测试用例。 每个案例以一行包含 2 个正整数 N 和 M(均不超过 105)开始,分别是总人数和好友关系数。 因此,这里的人从 1 到 N 编号。 然后是 M 行,每行包含一对朋友的索引,用空格分隔。 假设如果A是B的朋友,那么B是A的朋友。 然后是几个查询,每个查询占一行。 对于每行查询,K(3≤K≤N),首先给出该朋友圈的成员总数,然后是K个成员索引。 保证一个圆圈中的所有索引都是不同的。 当 K 为零时输入结束,并且不能处理这种情况。
Output Specification:
For each query, print in a line the members with top 3 indices of popularity in descending order of their IP’s. If there is a tie, output the one with the smaller number. The numbers must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
译:对于每个查询,按 IP 的降序将具有前 3 个流行指数的成员排成一行。 如果有平局,则输出数字较小的那个。 数字必须正好由 1 个空格分隔,并且行首或行尾不得有多余的空格。
Sample Input:
8 10
2 1
1 3
1 4
1 5
5 8
3 5
2 3
6 3
4 6
3 4
7 8 1 2 3 4 6 5
4 1 3 5 2
4 8 7 4 2
0
Sample Output:
3 1 4
1 3 2
2 4 7
坑点:
- 使用 bool 类型的领接矩阵 只能呐 18分 (最后两个测试点过不了,理由是超时 和 内存超限)
- 使用 unordered_map<long long , bool> 存储朋友关系( a * 100000 + b 可以作为哈希的唯一 key值) ,这样也会内存超限!
- 最后通过不停的修改,得到 邻接表 + 标记出现数组 + 结构体排序 可以满足要求
The Code:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 100010 ;
struct node{
int id ;
int cnt ;
bool flag ;
};
int n , m , k , te ;
bool cmp(node a , node b){
if(a.flag != b.flag) return a.flag > b.flag ; // 出现过 排在 未出现过之前
else if(a.cnt != b.cnt) return a.cnt > b.cnt ; // 朋友数多的 排在 朋友数少的之前
return a.id < b.id ; // id 小的排在 id 大的前
}
vector<node> ans ;
vector<int> nums ;
vector<int> g[maxn] ;
vector<bool> vis ;
int main(){
scanf("%d %d" ,&n , &m) ;
int a , b ;
for(int i = 0 ; i < m ; i ++){ // 输入图,无向图
scanf("%d %d" ,&a , &b) ;
g[a].push_back(b) ;
g[b].push_back(a) ;
}
ans.resize(n + 1) ;
vis.resize(n + 1) ;
while(true){
scanf("%d" ,&k);
if(k == 0) break ;
fill(vis.begin() , vis.end() , false ) ;
for(int i = 1 ; i <= n ; i ++)
ans[i].id = i , ans[i].cnt = 0 , ans[i].flag = false ;
nums.clear() ;
nums.resize(k) ;
for(int i = 0 ; i < k ; i ++){
scanf("%d" ,&nums[i]);
ans[nums[i]].flag = vis[nums[i]] = true ;
}
for(int i = 0 ; i < k ; i ++){
for(int j = 0 ; j < g[nums[i]].size() ; j ++){
if(vis[g[nums[i]][j]]){ // 是朋友关系,并且本次 circle 中出现过
ans[nums[i]].cnt ++ ;
ans[g[nums[i]][j]].cnt ++ ;
}
}
}
sort(ans.begin() + 1, ans.end() , cmp) ; // 按照题意排序规则排序
printf("%d" , ans[1].id ); // 输出本次 前三个 人气王
for(int i = 2 ; i <= 3 ; i ++)
printf(" %d" , ans[i].id );
printf("\n");
}
return 0 ;
}