文章目录

  • (递推) A1101 Quick Sort (25 分) 0.23
  • (静态二叉树+遍历) A1102 Invert a Binary Tree (25 分) 0.51
  • (数学问题) A1104 Sum of Number Segments (20 分) 0.32
  • (静态树+DFS) A1106 Lowest Price in Supply Chain (25 分) 0.42
  • (并查集) A1107 Social Clusters (30 分) 0.38
  • (字符串与数值转换) A1108 Finding Average (20 分) 0.26
  • (静态二叉树+判断CBT) A1110 Complete Binary Tree (25 分) 0.25
  • (字符串处理) A1112 Stucked Keyboard (20 分)
  • (水题) A1113 Integer Set Partition (25 分) 0.63
  • (静态/动态建立二叉查找树+DFS) A1115 Counting Nodes in a BST (30 分)
  • (简单模拟) A1116 Come on! Let's C (20 分) 0.40
  • (简单逻辑题) A1117 Eddington Number (25 分) 0.23
  • (并查集) A1118 Birds in Forest (25 分) 0.33
  • ☆☆☆ (二叉树+先序中序转后序) A1119 Pre- and Post-order Traversals (30 分) 0.36
  • (水题+简单哈希) A1120 Friend Numbers (20 分) 0.62
  • (简单模拟+STL) A1121 Damn Single (25 分) 0.35
  • (AVL树插入+建树+完全二叉树判断) A1123 Is It a Complete AVL Tree (30 分) 0.39
  • (汉密尔顿回路) A1122 Hamiltonian Cycle (25 分)
  • A1124 Raffle for Weibo Followers (20 分) 0.41
  • (排序+贪心) A1125 Chain the Ropes (25 分) 0.47
  • (欧拉通路/欧拉回路) A1126 Eulerian Path (25 分) 0.23
  • (二叉树+后序中序建树+层次遍历) A1127 ZigZagging on a Tree (30 分) 0.49
  • (简单逻辑) A1128 N Queens Puzzle (20 分)
  • (STL, set自定义排序规则) A1129 Recommendation System (25 分) 0.34
  • (简单数学) A1132 Cut Integer (20 分) 0.63
  • (静态链表) A1133 Splitting A Linked List (25 分) 0.32
  • (哈希散列+图的顶点覆盖) A1134 Vertex Cover (25 分)
  • (红黑树判断) A1135 Is It A Red-Black Tree (30 分)
  • (字符串操作) A1136 A Delayed Palindrome (20 分) 0.31
  • (排序+复杂模拟+map) A1137 Final Grading (25 分) 0.26
  • (二叉树+先序中序->后序) A1138 Postorder Traversal (25 分) 0.44
  • (模拟+STL应用) A1139 First Contact (30 分)
  • (字符串操作) A1140 Look-and-say Sequence (20 分) 0.46
  • (LCA+BST) A1143 Lowest Common Ancestor (30 分) 0.23
  • (简单模拟+STL) A1144 The Missing Number (20 分) 0.28
  • (拓扑排序+判断拓扑序列正误) A1146 Topological Order (25 分)
  • (大小堆判断+完全二叉树后序遍历) A1147 Heaps (30 分) 0.41
  • (逻辑题) A1148 Werewolf - Simple Version (20 分)
  • (STL的使用) A1149 Dangerous Goods Packaging (25 分) 0.38
  • (LCA+二叉树遍历+先序/中序) A1151 LCA in a Binary Tree (30 分) 0.26
  • (字符串处理) A1152 Google Recruitment (20 分) 0.24
  • (DFS+回溯+大小堆判断) A1155 Heap Paths (30 分)
  • (顶点着色+set+hash) A1154 Vertex Coloring (25 分)

(递推) A1101 Quick Sort (25 分) 0.23

There is a classical process named partition in the famous quick sort algorithm. In this process we typically choose one element as the pivot. Then the elements less than the pivot are moved to its left and those larger than the pivot to its right. Given N distinct positive integers after a run of partition, could you tell how many elements could be the selected pivot for this partition?

For example, given N=5 and the numbers 1, 3, 2, 4, and 5. We have:

1 could be the pivot since there is no element to its left and all the elements to its right are larger than it;
3 must not be the pivot since although all the elements to its left are smaller, the number 2 to its right is less than it as well;
2 must not be the pivot since although all the elements to its right are larger, the number 3 to its left is larger than it as well;
and for the similar reason, 4 and 5 could also be the pivot.

Hence in total there are 3 pivot candidates.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤10​5​​). Then the next line contains N distinct positive integers no larger than 10​9​​. The numbers in a line are separated by spaces.
  • Output Specification:
    For each test case, output in the first line the number of pivot candidates. Then in the next line print these candidates in increasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the end of each line.
  • Sample Input:
    5
    1 3 2 4 5
    
  • Sample Output:
    3
    1 4 5
    

与A1093 有几个PAT很像。另外这题的数值no larger than 10​9​​,在选择inf的时候必须小心,不然就会出错,我选择的是int范围的最大值,0x7fffffff,要记住的话很简单,7个f。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100, inf = 0x7fffffff;
int data[maxn], leftMax[maxn], rightMin[maxn];
//当某元素左边没有更大的元素, 右边没有更小的元素时为枢纽元
//或者说某元素大于左边最大, 小于右边最小时为枢纽元int main() {int n, cnt = 0; scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d", &data[i]);leftMax[0] = 0; //左边没有更大的数//leftMax[i]是i位前的所有元素中的最大值, 可以递推 for (int i = 1; i < n; i++) leftMax[i] = max(leftMax[i - 1], data[i - 1]);rightMin[n - 1] = inf; //右边没有更小的数for (int i = n - 2; i >= 0; i--) rightMin[i] = min(rightMin[i + 1], data[i + 1]);vector<int> ans; //记录所有主元和主元个数for (int i = 0; i < n; i++) if (data[i] > leftMax[i] && data[i] < rightMin[i]) ans.push_back(data[i]); //记录主元printf("%d\n", ans.size());for (int i = 0; i < ans.size(); i++) {if (i > 0) printf(" ");printf("%d", ans[i]); } printf("\n"); //必须要有换行return 0;
}

(静态二叉树+遍历) A1102 Invert a Binary Tree (25 分) 0.51

Now it’s your turn to prove that YOU CAN invert a binary tree!

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤10) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node from 0 to N−1, and gives the indices of the left and right children of the node. If the child does not exist, a - will be put at the position. Any pair of children are separated by a space.
  • Output Specification:
    For each test case, print in the first line the level-order, and then in the second line the in-order traversal sequences of the inverted tree. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.
  • Sample Input:
    8
    1 -
    - -
    0 -
    2 7
    - -
    - -
    5 -
    4 6
    
  • Sample Output:
    3 7 2 6 4 0 5 1
    6 5 7 4 3 2 0 1
    

这道题题意是:给出一棵二叉树的全部结点和左右孩子的编号,然后反转二叉树(把每个结点的左右子树交换),输出交换后的层序和中序序列
注意点:

  • 这里使用二叉树的静态写法;
  • 从这些结点中找到树的根结点,在于寻找一个结点,它不是任何结点的孩子,开一个checked数组,在输入的时候记录;
  • 不一定需要实际的交换,这里交换后的层序遍历可以通过先push右子树的结点,再push左子树的结点;交换后的中序遍历,就是按右子树-根结点-左子树的顺序进行遍历。稍微修改原来的代码就可以了;
  • 如果要进行实际的左右子树交换,可以使用先序/后序遍历,在访问根结点的时候交换左右孩子结点。
#include <bits/stdc++.h>
#define Null (-1)
using namespace std;
struct BTreeNode {int left, right;
} tree[12];int CreateTree() {char cl, cr;int n, root = Null;scanf("%d\n", &n);int checked[n + 1];memset(checked, 0, sizeof(checked));if (n) {for (int i = 0; i < n; i++) { //结点from 0 to N-1scanf("%c %c\n", &cl, &cr);if (cl != '-') {tree[i].left = cl - '0';checked[tree[i].left] = 1; //该结点有父结点指向} else tree[i].left = Null;if (cr != '-') {tree[i].right = cr - '0';checked[tree[i].right] = 1; //该结点有父结点指向} else tree[i].right = Null;}}for (int i = 0; i < n; i++) {if (checked[i] == 0) {root = i;break;}}return root;
}
vector<int> lev, in;
void Levelorder(int r) {queue<int> q;q.push(r);while (!q.empty()) {int t = q.front(); q.pop();lev.push_back(t);if (tree[t].right != Null) q.push(tree[t].right);if (tree[t].left != Null) q.push(tree[t].left);}
}void Inorder(int r) {if (r != Null) {Inorder(tree[r].right);in.push_back(r);Inorder(tree[r].left);}
}int main() {int r = CreateTree();Levelorder(r);Inorder(r);for (int i = 0; i < lev.size(); i++) {if (i > 0) printf(" ");printf("%d", lev[i]);}printf("\n");for (int i = 0; i < in.size(); i++) {if (i > 0) printf(" ");printf("%d", in[i]);}return 0;
}

(数学问题) A1104 Sum of Number Segments (20 分) 0.32

a segment is defined to be a consecutive subsequence. 多举几个例子,总结一下规律就好了。

#include <bits/stdc++.h>
int n;
double a, sum = 0.0;
int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%lf", &a);sum += a * (n - i) * (i + 1);} printf("%.2lf\n", sum);return 0;
}

值得一提的是,当我如下写的时候会有两个测试点错误……原因在哪里呢?后两个测试点用的时间明显要长许多,而且...a positive integer N, the size of the sequence which is no more than 10​5​​,N positive numbers in the sequence, each no more than 1.0。那么,如果我用105个数字,这个式子计算中途会怎么样呢?

#include <bits/stdc++.h>
int n;
double a, sum = 0.0;
int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%lf", &a);sum += (n - i) * (i + 1) * a;} printf("%.2lf\n", sum);return 0;
}

遗憾的是,我们无法自己输入这么多的数字。所以魔改了一下,发现不同了。表达式中隐式的类型转换是顺着方向来的,结果可能在(n - i) * (i + 1)整数运算时就溢出了。

#include <bits/stdc++.h>
using namespace std;
const int n = 100000;
double sum = 0.0;
double a[n];
int main() {fill(a, a + n, 0.1); //全部设置成0.1 for (int i = 0; i < n; i++) //sum += (n - i) * (i + 1) * a[i]; //537846486599.88 溢出!//sum += a[i] * (n - i) * (i + 1);   //16667166670017.85sum += 1.0 * (n - i) * (i + 1) * a[i]; //16667166670017.85printf("%.2lf\n", sum);return 0;
}

(静态树+DFS) A1106 Lowest Price in Supply Chain (25 分) 0.42

A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone involved in moving a product from supplier to customer.

Starting from one root supplier, everyone on the chain buys products from one’s supplier in a price P and sell or distribute them in a price that is r% higher than P. Only the retailers will face the customers. It is assumed that each member in the supply chain has exactly one supplier except the root supplier, and there is no supply cycle.

Now given a supply chain, you are supposed to tell the lowest price a customer can expect from some retailers.

  • Input Specification:
    Each input file contains one test case. For each case, The first line contains three positive numbers: N (≤10​5​​), the total number of the members in the supply chain (and hence their ID’s are numbered from 0 to N−1, and the root supplier’s ID is 0); P, the price given by the root supplier; and r, the percentage rate of price increment for each distributor or retailer. Then N lines follow, each describes a distributor or retailer in the following format:

    K​i​​ ID[1] ID[2] ... ID[K​i​​]
    

    where in the i-th line, K​i​​ is the total number of distributors or retailers who receive products from supplier i, and is then followed by the ID’s of these distributors or retailers. K​j​​ being 0 means that the j-th member is a retailer. All the numbers in a line are separated by a space.

  • Output Specification:
    For each test case, print in one line the lowest price we can expect from some retailers, accurate up to 4 decimal places, and the number of retailers that sell at the lowest price. There must be one space between the two numbers. It is guaranteed that the all the prices will not exceed 10​10​​.
  • Sample Input:
    10 1.80 1.00
    3 2 3 5
    1 9
    1 4
    1 7
    0
    2 6 1
    1 8
    0
    0
    0
    
  • Sample Output:
    1.8362 2
    

题意:给出一棵销售供应的树,树根唯一,树根处的货物价格为P,然后从根结点开始每往子结点走一层,该层货物价格增加r%,求出叶子结点能够获得的最低价格以及最低价格的叶子结点的个数。
思路:DFS,开全局变量ans和num,用来记录最低的价格和价格最低的叶子结点的个数。如果当前叶子结点的价格低于全局最低价格,则更新全局最低价格,置num=1;等于的话就让num+1。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, num; //n表示结点个数, num表示最低价格结点数目
double p, r, ans = 10e10 + 9;
vector<int> node[maxn];void DFS(int root, double price) {if (node[root].size() == 0) {if (price < ans) {ans = price; num = 1;  } else if (price == ans) num++;return;} else {for (int i = 0; i < node[root].size(); i++) {int child = node[root][i];DFS(child, price * (1.0 + r));}}
}
int main() {scanf("%d%lf%lf", &n, &p, &r);int k, child;r /= 100.0;for (int i = 0; i < n; i++) {scanf("%d", &k);if (k == 0) continue;else {for (int j = 0; j < k; j++) {scanf("%d", &child);node[i].push_back(child);}}}DFS(0, p);printf("%.4lf %d\n", ans, num);return 0;
}

(并查集) A1107 Social Clusters (30 分) 0.38

When register on a social network, you are always asked to specify your hobbies in order to find some potential friends with the same hobbies. A social cluster is a set of people who have some of their hobbies in common. You are supposed to find all the clusters.

  • Input Specification:
    Each input file contains one test case. For each test case, the first line contains a positive integer N (≤1000), the total number of people in a social network. Hence the people are numbered from 1 to N. Then N lines follow, each gives the hobby list of a person in the format:

    K​i​​: h​i​​[1] h​i​​[2] ... h​i​​[K​i​​]
    

    where K​i​​ (>0) is the number of hobbies, and h​i​​[j] is the index of the j-th hobby, which is an integer in [1, 1000].

  • Output Specification:
    For each case, print in one line the total number of clusters in the network. Then in the second line, print the numbers of people in the clusters in non-increasing order. The numbers must be separated by exactly one space, and there must be no extra space at the end of the line.
  • Sample Input:
    8
    3: 2 7 10
    1: 4
    2: 5 3
    1: 4
    1: 3
    1: 4
    4: 6 8 1 5
    1: 4
    
  • Sample Output:
    3
    4 3 1
    
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int father[maxn], course[maxn] = {0};
int n, cnt, hobby;
int findfather(int x) {if (father[x] < 0) return x;else return father[x] = findfather(father[x]);
}
void setUnion(int r1, int r2) {if (father[r1] < father[r2]) {father[r1] += father[r2];father[r2] = r1;} else {father[r2] += father[r1];father[r1] = r2;}
}
bool cmp(int a, int b) { return a > b; }
int main() {scanf("%d", &n);memset(father, -1, sizeof(father));memset(course, 0, sizeof(course));for (int i = 1; i <= n; i++) {scanf("%d:", &cnt); //兴趣个数while (cnt--) {scanf("%d", &hobby);if (course[hobby] == 0) course[hobby] = i; //活动被某人喜欢  else { //喜欢的活动已经有同样的人喜欢了, 和他们合并为1个集合 int root1 = findfather(i), root2 = findfather(course[hobby]);if (root1 != root2) setUnion(root1, root2);}}}int ans = 0;vector<int> v;for (int i = 1; i <= n; i++) {if (father[i] < 0) {ans++; //集合个数 v.push_back(-father[i]); //每个集合的大小 }}sort(v.begin(), v.end(), cmp);printf("%d\n", ans);for (int i = 0; i < v.size(); i++) {if (i > 0) printf(" ");printf("%d", v[i]);}return 0;
}

(字符串与数值转换) A1108 Finding Average (20 分) 0.26

乙级做过的题目。用string+stod/to_string进行转换要处理异常,反而麻烦。
sscanf() – 从一个字符串中读进与指定格式相符的数据
sprintf() – 字符串格式化命令,主要功能是把格式化的数据写入某个字符串中

#include <bits/stdc++.h>
using namespace std;int main() {int N, cnt = 0;double sum = 0.0, temp;char a[100], b[100]; scanf("%d", &N);while (N--) {scanf("%s", a);sscanf(a, "%lf", &temp); //从字符数组a中以浮点数的形式读入 //cout << a << " = " << temp << " = ";sprintf(b, "%.2lf", temp); //将浮点数temp以小数点后两位精度的形式输出到字符数组b中 //cout << b << endl;int flag = 0;for (int j = 0; a[j]; j++) //以s为基准 if (a[j] != b[j]) flag = 1; if (flag || temp > 1000 || temp < -1000) {printf("ERROR: %s is not a legal number\n", a);continue;} else {sum += temp;cnt++;}}if (cnt == 1) printf("The average of 1 number is %.2lf", sum);else if (cnt > 0) printf("The average of %d numbers is %.2lf", cnt, sum / cnt);else printf("The average of 0 numbers is Undefined");return 0;
}

(静态二叉树+判断CBT) A1110 Complete Binary Tree (25 分) 0.25

Given a tree, you are supposed to tell if it is a complete binary tree.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤20) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a - will be put at the position. Any pair of children are separated by a space.
  • Output Specification:
    For each case, print in one line YES and the index of the last node if the tree is a complete binary tree, or NO and the index of the root if not. There must be exactly one space separating the word and the number.
  • Sample Input 1:
    9
    7 8
    - -
    - -
    - -
    0 1
    2 3
    4 5
    - -
    - -
    
  • Sample Output 1:
    YES 8
    
  • Sample Input 2:
    8
    - -
    4 5
    0 6
    - -
    2 3
    - 7
    - -
    - -
    
  • Sample Output 2:
    NO 1
    

题意:给出一棵树,判断其是否是完全二叉树,是则输出最后一个结点在树中的下标,否则输出根结点的下标。
思路:完全二叉树从上到下从做到右一定是从1-N,会把前面的下标充满,最大的下标值==最大的结点数;非完全二叉树一定有位置为空,会往后挤,最大的下标值>最大的结点数。
注意点:结点可以是2位数的,不能用字符输入

#include <bits/stdc++.h>
using namespace std;
const int maxn = 30;
struct Node {int left, right;
} tree[maxn];
int n, ans, Max = -1;
void DFS(int root, int index) {if (index > Max) {Max = index; //更新(完全二叉树)最大的下标值ans = root; //更新最后一个结点的下标 }if (tree[root].left != -1) DFS(tree[root].left, index * 2);if (tree[root].right != -1) DFS(tree[root].right, index * 2 + 1);
}int main() {scanf("%d\n", &n);string s1, s2;int noRoot[maxn], root = 0;memset(noRoot, 0, sizeof(noRoot));for (int i = 0; i < n; i++) {cin >> s1 >> s2;if (s1 != "-") {tree[i].left = stoi(s1);noRoot[tree[i].left] = 1;} else tree[i].left = -1;if (s2 != "-") {tree[i].right = stoi(s2);noRoot[tree[i].right] = 1;} else tree[i].right = -1;}while (noRoot[root] != 0) root++;DFS(root, 1); //根结点为1if (Max == n) printf("YES %d\n", ans); else printf("NO %d\n", root);return 0;
}

(字符串处理) A1112 Stucked Keyboard (20 分)

On a broken keyboard, some of the keys are always stucked. So when you type some sentences, the characters corresponding to those keys will appear repeatedly on screen for k times.
Now given a resulting string on screen, you are supposed to list all the possible stucked keys, and the original string.

Notice that there might be some characters that are typed repeatedly. The stucked key will always repeat output for a fixed k times whenever it is pressed. For example, when k=3, from the string thiiis iiisss a teeeeeest we know that the keys i and e might be stucked, but s is not even though it appears repeatedly sometimes. The original string could be this isss a teest.

  • Input Specification:
    Each input file contains one test case. For each case, the 1st line gives a positive integer k (1<k≤100) which is the output repeating times of a stucked key. The 2nd line contains the resulting string on screen, which consists of no more than 1000 characters from {a-z}, {0-9} and _. It is guaranteed that the string is non-empty.
  • Output Specification:
    For each test case, print in one line the possible stucked keys, in the order of being detected. Make sure that each key is printed once only. Then in the next line print the original string. It is guaranteed that there is at least one stucked key.
  • Sample Input:
    3
    caseee1__thiiis_iiisss_a_teeeeeest
    
  • Sample Output:
    ei
    case1__this_isss_a_teest
    

18分,有一个测试点死活过不了,以后回来看。

#include <bits/stdc++.h>
using namespace std;
int hashTable[130] = {0};
int main() {int k, j;string s;cin >> k >> s; //k>1string old = "";map<char, int> mp;for (int i = 0; i < s.size(); ) {char c1 = s[i];j = i + 1;while (mp[c1] == 0 && s[j] == c1) j++; //字符出现的次数 int n = (j - i) % k, m = (j - i) / k;if (n == 0) { //首次出现多个k次, 可能是stuckedKey if (hashTable[c1] == 0) printf("%c", c1);hashTable[c1] = 1; //按顺序输出stuckedKey, 只输出一次 for (int v = 0; v < m; v++) old += c1;} else {mp[c1] = 1; //如果首次没有出现k次, 以后也不会是  for (int v = 0; v < j - i; v++) old += c1;}i = j;}cout << endl << old << endl; return 0;
}

(水题) A1113 Integer Set Partition (25 分) 0.63

将一个数字集合划分成两个集合,使得两个集合的大小之差的绝对值最小,两个集合各自的元素和之差的绝对值最大。很简单的题目,而且也做过了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
int data[maxn];
int main() {int n; scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d", &data[i]);sort(data, data + n); //从小到大排序int s1 = 0, s2 = 0;for (int i = 0; i < n; i++) {if (i < n / 2) s1 += data[i];else if (i >= n / 2) s2 += data[i];} //奇数时|n1-n2|为1, 偶数时为0printf("%d %d", n % 2 ? 1 : 0, s2 - s1);return 0;
}

(静态/动态建立二叉查找树+DFS) A1115 Counting Nodes in a BST (30 分)

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

The left subtree of a node contains only nodes with keys less than or equal to the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

Insert a sequence of numbers into an initially empty binary search tree. Then you are supposed to count the total number of nodes in the lowest 2 levels of the resulting tree.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤1000) which is the size of the input sequence. Then given in the next line are the N integers in [−1000, 1000] which are supposed to be inserted into an initially empty binary search tree.
  • Output Specification:
    For each case, print in one line the numbers of nodes in the lowest 2 levels of the resulting tree in the format:

    n1 + n2 = n
    

    where n1 is the number of nodes in the lowest level, n2 is that of the level above, and n is the sum.

  • Sample Input:
    9
    25 30 42 16 20 20 35 -5 28
    
  • Sample Output:
    2 + 4 = 6
    

题意:给出一个整数序列,建立一棵二叉排序树,建树的过程就是不断往空树中插入的过程(和插入法建堆很相似,但是建堆还是有点要说的)。最后,输出最低两层的结点数及其总数。
思路:可以静态建立二叉树,关键在于newNode函数的写法。然后DFS,不断更新最大层数,记录每层的结点数,最后输出即可。
注意点:

  • 不要搞错n1和n2,n1是最低层的结点数,n2是之上一层的结点数;
  • 一个元素小于等于结点值,要递归插入左子树(题目中说了),不然会有几个测试点错误,而你很难检查出来。
/* 静态写法 */
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
struct Node{int data, left, right;
} tree[maxn];
int Index = 0;
int newNode(int v) {tree[Index].data = v;tree[Index].left = tree[Index].right = -1;return Index++;
}
void insert(int &root, int t) { //声明为引用, 递归改变子树的根结点if (root == -1) {root = newNode(t);return;} else {if (tree[root].data < t) insert(tree[root].right, t);else if (tree[root].data >= t) //一个元素小于等于结点值, 递归插入左子树insert(tree[root].left, t);}
}int nodeNums[maxn] = {0}, level = 0;
void DFS(int root, int depth) {if (depth > level) level = depth; //更新层数 nodeNums[depth]++; if (tree[root].left != -1) DFS(tree[root].left, depth + 1);if (tree[root].right != -1) DFS(tree[root].right, depth + 1);
}int main() {int n, t, root = -1;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &t);insert(root, t); //第一次更新后的root为整棵树的根结点 }DFS(root, 0); //根结点为第0层int ans = nodeNums[level - 1] + nodeNums[level]; printf("%d + %d = %d\n", nodeNums[level], nodeNums[level - 1], ans);return 0;
}
/* 动态写法, 小心段错误! */
#include <bits/stdc++.h>
using namespace std;
struct Node{int data;Node *left, *right;
};
Node *newNode(int v) {Node *root = new Node;root->data = v;root->left = root->right = NULL;return root;
}
Node *insert(Node *root, int t) {if (root == NULL) {root = newNode(t);} else {if (t <= root->data) root->left = insert(root->left, t);else if (t > root->data) root->right = insert(root->right, t);}return root;
}int nodeNums[1010] = {0}, level = 0;
void DFS(Node *root, int depth) { if (root == NULL) {if (depth > level) level = depth; //更新层数为最大层+1return; }nodeNums[depth]++; DFS(root->left, depth + 1);DFS(root->right, depth + 1);
}int main() {int n, t;Node *root = NULL;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &t);root = insert(root, t); //第一次更新后的root为整棵树的根结点 }DFS(root, 0); //根结点为第0层int ans = nodeNums[level - 1] + nodeNums[level - 2]; printf("%d + %d = %d\n", nodeNums[level - 1], nodeNums[level - 2], ans);return 0;
}

(简单模拟) A1116 Come on! Let’s C (20 分) 0.40

乙级做过的题目。

#include <bits/stdc++.h>
using namespace std;
bool isPrime(int n) {if (n <= 1) return false;int sqr = (int)sqrt(1.0 * n);for (int i = 2; i <= sqr; i++) if (n % i == 0) return false;return true;
}
string given[3] = {"Mystery Award", "Minion", "Chocolate"};
struct node {int id, checked, type;node() { id = -1; checked = 0; } //区分有没有这个结点
};
int main() {int n, t;scanf("%d", &n);vector<node> vi(10010);for (int i = 1; i <= n; i++) {scanf("%d", &t);vi[t].id = i;if (i == 1) vi[t].type = 0;else if (isPrime(i)) vi[t].type = 1;else vi[t].type = 2;}int k; scanf("%d", &k);while (k--) {scanf("%d", &t);if (vi[t].id != -1) {if (vi[t].checked == 0) {printf("%04d: ");cout << given[vi[t].type] << endl;vi[t].checked = 1;} else printf("%04d: Checked\n", t);} else printf("%04d: Are you kidding?\n", t);}return 0;
}

(简单逻辑题) A1117 Eddington Number (25 分) 0.23

British astronomer Eddington liked to ride a bike. It is said that in order to show off his skill, he has even defined an “Eddington number”, E – that is, the maximum integer E such that it is for E days that one rides more than E miles. Eddington’s own E was 87.

Now given everyday’s distances that one rides for N days, you are supposed to find the corresponding E (≤N).

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤10​5​​), the days of continuous riding. Then N non-negative integers are given in the next line, being the riding distances of everyday.
  • Output Specification:
    For each case, print in a line the Eddington number for these N days.
  • Sample Input:
    10
    6 7 6 9 3 10 8 2 7 8
    
  • Sample Output:
    6
    

乙级做过的题目,爱丁顿数。为求出E天每天骑车距离大于E的爱丁顿数E,可以先将骑车距离序列从大到小排序,每天骑车的距离大于天数,天数就+1,直到某天骑车距离小于等于天数为止,这就是满足每天骑车的距离大于天数的最大天数E

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int d[maxn];
bool cmp(int a, int b) { return a > b; }
int main() {int n, e = 0;scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d", &d[i]);sort(d, d + n, cmp); //从小到大排列while (e < n && d[e] > e + 1) e++; //e+1表示骑车的天数, a[e]表示该天骑车的距离printf("%d\n", e);    return 0;
}

(并查集) A1118 Birds in Forest (25 分) 0.33

Some scientists took pictures of thousands of birds in a forest. Assume that all the birds appear in the same picture belong to the same tree. You are supposed to help the scientists to count the maximum number of trees in the forest, and for any pair of birds, tell if they are on the same tree.

  • Input Specification:
    Each input file contains one test case. For each case, the first line contains a positive number N (≤10​4​​) which is the number of pictures. Then N lines follow, each describes a picture in the format:

    K B​1​​ B​2​​ ... B​K​​
    

    where K is the number of birds in this picture, and B​i​​’s are the indices of birds. It is guaranteed that the birds in all the pictures are numbered continuously from 1 to some number that is no more than 10​4​​.
    After the pictures there is a positive number Q (≤10​4​​) which is the number of queries. Then Q lines follow, each contains the indices of two birds.
    Output Specification:

For each test case, first output in a line the maximum possible number of trees and the number of birds. Then for each query, print in a line Yes if the two birds belong to the same tree, or No if not.
Sample Input:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

Sample Output:

2 10
Yes
No

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int father[maxn] = {0}, picture[maxn];
void initialize() { //初始化for (int i = 0; i < maxn; i++) father[i] = -1;
}
int findfather(int x) { //路径压缩if (father[x] < 0) return x;else return father[x] = findfather(father[x]);
}
void setUnion(int r1, int r2) { //按大小归并集合if (father[r1] < father[r2]) {father[r1] += father[r2];father[r2] = r1;} else {father[r2] += father[r1];father[r1] = r2;}
}
int main() {int n, k, m, maxid = 0, id1, id2;scanf("%d", &n);initialize();for (int i = 0; i < n; i++) {scanf("%d", &k);for (int j = 0; j < k; j++) {scanf("%d", &picture[j]);if (picture[j] > maxid) maxid = picture[j]; //最大N}for (int j = 0; j < k - 1; j++) {int r1 = findfather(picture[j]), r2 = findfather(picture[j + 1]);if (r1 != r2) setUnion(r1, r2); //合并两个集合}}int ans = 0;for (int i = 1; i <= maxid; i++)  if (father[i] < 0) ans++;printf("%d %d\n", ans, maxid);scanf("%d", &m);for (int i = 0; i < m; i++) {scanf("%d%d", &id1, &id2);int r1 = findfather(id1), r2 = findfather(id2);if (r1 == r2) printf("Yes\n");else printf("No\n");}return 0;
}

☆☆☆ (二叉树+先序中序转后序) A1119 Pre- and Post-order Traversals (30 分) 0.36

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversal sequences. However, if only the postorder and preorder traversal sequences are given, the corresponding tree may no longer be unique.

Now given a pair of postorder and preorder traversal sequences, you are supposed to output the corresponding inorder traversal sequence of the tree. If the tree is not unique, simply output any one of them.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤ 30), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.
  • Output Specification:
    For each test case, first printf in a line Yes if the tree is unique, or No if not. Then print in the next line the inorder traversal sequence of the corresponding binary tree. If the solution is not unique, any answer would do. It is guaranteed that at least one solution exists. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.
  • Sample Input 1:
    7
    1 2 3 4 6 7 5
    2 6 7 4 5 3 1
    
  • Sample Output 1:
    Yes
    2 1 6 4 7 3 5
    
  • Sample Input 2:
    4
    1 2 3 4
    2 4 3 1
    
  • Sample Output 2:
    No
    2 1 3 4
    

题目大意:给出一棵树的结点个数n,以及它的前序遍历和后序遍历,输出它的中序遍历,如果中序遍历不不唯一就输出No,且输出其中一个中序即可,如果中序遍历唯一就输出Yes,并输出它的中序。

分析:用unique标记是否唯一,如果为true就表示中序是唯一的。

已知二叉树的前序和后序是无法唯一确定一颗二叉树的,因为可能会存在多种情况,这种情况就是一个结点可能是根的左孩子也有可能是根的右孩子,如果发现了了一个无法确定的状态,置unique = false,又因为题目只需要输出一个方案,可以假定这个不不可确定的孩子的状态是右孩子

接下来的问题是如何求根结点和左右孩子划分的问题了了,首先我们需要知道树的表示范围,需要四个变量量,分别是前序的开始的地方prel,前序结束的地方prer,后序开始的地方postl,后序结束的地方postr,前序的开始的第一个应该是后序的最后一个是相等的,这个结点就是根结点,以后序的根结点的前面一个结点作为参考,寻找这个结点在前序的位置,就可以根据这个位置来划分左右孩子,递归处理

#include <bits/stdc++.h>
using namespace std;
vector<int> in, pre, post;
bool Unique = true; //标志可以构建出唯一一棵二叉树出来
void getIn(int preLeft, int preRight, int postLeft, int postRight) {if (preLeft == preRight) {in.push_back(pre[preLeft]);return;} if (pre[preLeft] == post[postRight]) {int i = preLeft + 1;while (i <= preRight && pre[i] != post[postRight - 1]) i++;if (i - preLeft > 1) {getIn(preLeft + 1, i - 1, postLeft, postLeft + (i - preLeft - 1) - 1);} else Unique = false;in.push_back(post[postRight]);getIn(i, preRight, postLeft + (i - preLeft - 1), postRight - 1);}
}int main() {int n; scanf("%d", &n);pre.resize(n), post.resize(n);for (int i = 0; i < n; i++) scanf("%d", &pre[i]);for (int i = 0; i < n; i++) scanf("%d", &post[i]);getIn(0, n - 1, 0, n - 1);//输出结果printf("%s\n%d", Unique == true ? "Yes" : "No", in[0]);for (int i = 1; i < in.size(); i++) printf(" %d", in[i]);printf("\n");return 0;
}

(水题+简单哈希) A1120 Friend Numbers (20 分) 0.62

很简单的题目,而且做过。

#include <bits/stdc++.h>
using namespace std;
int main() {map<int, int> cnt; //存储拥有某个朋友ID的人数int n, t; scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &t);int sum = 0;do {sum += t % 10;t /= 10;} while (t);cnt[sum]++;}printf("%d\n", cnt.size()); //输出不同的朋友证号的个数int k = 0;for (auto it : cnt) {printf("%d", it.first); //输出朋友IDif (++k < cnt.size()) printf(" ");}return 0;
}

(简单模拟+STL) A1121 Damn Single (25 分) 0.35

乙级做过的题目,单身狗。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
int cp[maxn]; //00000到99999
int main() {memset(cp, -1, sizeof(cp));int n, p1, p2;scanf("%d", &n);while (n--) {scanf("%d%d", &p1, &p2);cp[p1] = p2;cp[p2] = p1;}int m; scanf("%d", &m); //≤10000int people[m];for (int i = 0; i < m; i++){scanf("%d", &people[i]);}int sinNum = 0, sinPerson[m + 10];for (int i = 0; i < m; i++) {if (cp[people[i]] == -1) sinPerson[sinNum++] = people[i]; //伴侣对中没有这个人, 说明是单身狗 else {int t = cp[people[i]], j = 0; //有伴侣找找伴侣来了没有 while (j < m && people[j] != t) j++;if (j >= m) sinPerson[sinNum++] = people[i]; //他的伴侣没来, 落单 }}sort(sinPerson, sinPerson + sinNum);printf("%d\n", sinNum); for (int i = 0; i < sinNum; i++) {if (i > 0) printf(" ");printf("%05d", sinPerson[i]);  }return 0;
}

(AVL树插入+建树+完全二叉树判断) A1123 Is It a Complete AVL Tree (30 分) 0.39

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.


Now given a sequence of insertions, you are supposed to output the level-order traversal sequence of the resulting AVL tree, and to tell if it is a complete binary tree.

  • Input Specification:
    Each input file contains one test case. For each case, the first line contains a positive integer N (≤ 20). Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
  • Output Specification:
    For each test case, insert the keys one by one into an initially empty AVL tree. Then first print in a line the level-order traversal sequence of the resulting AVL 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. Then in the next line, print YES if the tree is complete, or NO if not.
  • Sample Input 1:
    5
    88 70 61 63 65
    
  • Sample Output 1:
    70 63 88 61 65
    YES
    
  • Sample Input 2:
    8
    88 70 61 96 120 90 65 68
    
  • Sample Output 2:
    88 65 96 61 70 90 120 68
    NO
    

判断是不是完全二叉树,可以通过DFS也可以通过BFS(层次遍历)进行,我的代码里面先写了层次遍历,然后再用DFS判断是否是完全二叉树。实际上可以将它们合在一起。在层序遍历中,看在出现了一个孩子为空的结点之后是否还会出现孩子结点不为空的结点,如果出现了就不是完全二叉树。

#include <bits/stdc++.h>
using namespace std;
struct node {int v, h;node *l, *r;
};
node* newNode(int v) {node *root = new node;root->v = v;root->h = 1; root->l = root->r = NULL;return root;
}
int getHeight(node *root) {if (root == NULL) return 0;else return root->h;
}
int getFactor(node *root) {return getHeight(root->l) - getHeight(root->r);
}
void updateHeight(node *root) {root->h = max(getHeight(root->l), getHeight(root->r)) + 1;
}
void L(node *&root) { //左旋拎右左挂右 node *temp = root->r;root->r = temp->l;temp->l = root; //先更新底层的子结点root, 再更新现在作为根的temp的高度updateHeight(root); updateHeight(temp);root = temp;
}
void R(node *&root) { //右旋拎左右挂左 node *temp = root->l;root->l = temp->r;temp->r = root;updateHeight(root); updateHeight(temp);root = temp;
}
void insert(node *&root, int v) {if (root == NULL) {root = newNode(v);return;}if (v < root->v) {insert(root->l, v);updateHeight(root);int nf = getFactor(root);if (nf > 1) {int bf = getFactor(root->l);if (bf > 0) R(root); //LL型 else {    L(root->l); R(root); } //LR型 } } else {insert(root->r, v);updateHeight(root);int nf = getFactor(root);if (nf < -1) {int bf = getFactor(root->r);if (bf < 0) L(root); //RR型 else {  R(root->r); L(root); } //RL型 }       }
}
int n, a[20], num = 0, MAX = -1;
void Levelorder(node *root) {queue<node *> q;q.push(root); while (!q.empty()) {node *t = q.front(); q.pop();printf("%d", t->v);num++;if (num < n) printf(" ");if (t->l != NULL) q.push(t->l);if (t->r != NULL) q.push(t->r); }
}
void DFS(node *root, int index) { //判断是否是完全二叉树if (index > MAX) MAX = index; //更新(完全二叉树)最大的下标值if (root->l != NULL) DFS(root->l, index * 2);if (root->r != NULL) DFS(root->r, index * 2 + 1);
}
int main() {scanf("%d", &n);node *root = NULL;for (int i = 0; i < n; i++) {scanf("%d", &a[i]);insert(root, a[i]);}Levelorder(root);DFS(root, 1);if (MAX == n) printf("\nYES\n");else printf("\nNO\n");return 0;
}

(汉密尔顿回路) A1122 Hamiltonian Cycle (25 分)

The “Hamilton cycle problem” is to find a simple cycle that contains every vertex in a graph. Such a cycle is called a “Hamiltonian cycle”.

In this problem, you are supposed to tell if a given cycle is a Hamiltonian cycle.

  • Input Specification:
    Each input file contains one test case. For each case, the first line contains 2 positive integers N (2<N≤200), the number of vertices, and M, the number of edges in an undirected graph. Then M lines follow, each describes an edge in the format Vertex1 Vertex2, where the vertices are numbered from 1 to N. The next line gives a positive integer K which is the number of queries, followed by K lines of queries, each in the format:

    n V​1​​ V​2​​ ... V​n​​
    

    where n is the number of vertices in the list, and V​i​​’s are the vertices on a path.

  • Output Specification:
    For each query, print in a line YES if the path does form a Hamiltonian cycle, or NO if not.
  • Sample Input:
    6 10
    6 2
    3 4
    1 5
    2 5
    3 1
    4 1
    1 6
    6 3
    1 2
    4 5
    6
    7 5 1 4 3 6 2 5
    6 5 1 4 3 6 2
    9 6 2 1 6 3 4 5 2 6
    4 1 2 5 1
    7 6 1 3 4 5 2 6
    7 6 1 2 5 4 3 1
    
  • Sample Output:
    YES
    NO
    NO
    NO
    YES
    NO
    

题意:给出一张无向图,判断给出的多个路径是不是汉密尔顿回路。汉密尔顿回路是一条简单回路,途径图中每个结点一次且仅一次,最后回到起点。
思路:判断这条路径是否是汉密尔顿通路,无非是看这条路径的结点数是否为n+1(回路)、多走重复结点,当前面满足时看少走、成环(可以用set去重,因为结点编号从1到n)。最后还要判断这条路是否是通路。两个条件都成立则为汉密尔顿通路。
注意点:

  • 使用邻接矩阵更加方便,因为这样有利于判断两个结点是否连通。
#include <bits/stdc++.h>
using namespace std;int main() {/* 汉密尔顿回路: 包含了图中每个结点的简单回路, 即每个结点仅出现一次 */int n, m, cnt, k, a[210][210] = {0};cin >> n >> m;for (int i = 0; i < m; i++) {int t1, t2;scanf("%d%d", &t1, &t2);a[t1][t2] = a[t2][t1] = 1;}cin >> cnt;while (cnt--) {cin >> k;vector<int> v(k);set<int> s;int f1 = 1, f2 = 1;for (int i = 0; i < k; i++) {scanf("%d", &v[i]);s.insert(v[i]);}//汉密尔顿回路:连通图; 回路结点数k为n+1; 最后一个结点为开始结点if (s.size() != n || k - 1 != n || v[0] != v[k-1]) f1 = 0;for (int i = 0; i < k - 1; i++) //给出的路径上面两点连通if (a[v[i]][v[i + 1]] == 0) f2 = 0;printf("%s", f1 && f2 ? "YES\n" : "NO\n");}return 0;
}

A1124 Raffle for Weibo Followers (20 分) 0.41

乙级做过的题目,微博抽奖。

#include <bits/stdc++.h>
using namespace std;int main() {int m, n, s;scanf("%d%d%d", &m, &n, &s);map<string, int> mp;vector<string> people(m); //m个元素的变长数组 for (int i = 0; i < m; i++) {cin >> people[i];mp.insert(make_pair(people[i], 0)); //没有访问过 }int cnt = 0; //中奖人数for (int i = s - 1; i < m; ) {if (mp[people[i]] == 0) {cnt++; //中奖人数+1 cout << people[i] << endl;mp[people[i]] = 1; i += n; //查找下一个中奖间隔的人 } else i++; } if (!cnt) printf("Keep going...\n");return 0;
}

(排序+贪心) A1125 Chain the Ropes (25 分) 0.47

Given some segments of rope, you are supposed to chain them into one rope. Each time you may only fold two segments into loops and chain them into one piece, as shown by the figure. The resulting chain will be treated as another segment of rope and can be folded again. After each chaining, the lengths of the original two segments will be halved.


Your job is to make the longest possible rope out of N given segments.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (2≤N≤10​4​​). Then N positive integer lengths of the segments are given in the next line, separated by spaces. All the integers are no more than 10​4​​.
  • Output Specification:
    For each case, print in a line the length of the longest possible rope that can be made by the given segments. The result must be rounded to the nearest integer that is no greater than the maximum length.
  • Sample Input:
    8
    10 15 12 3 4 13 1 15
    
  • Sample Output:
    14
    

乙级做过的题目。其实不要多想,这道题很好做。它给出了很多绳段,每两段分别折叠后合在一起,长度减半,求全部绳段照这种方式合并得到的最长的绳索的长度。

先排序,然后从小到大合并,这样就会越合并越大,最后给出的就是最长的长度。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int main() {int n; cin >> n;vector<ll> v(n);for (int i = 0; i < n; i++) scanf("%lld", &v[i]);sort(v.begin(), v.end());ll ans = (v[0] + v[1]) / 2;for (int i = 2; i < n; i++) ans = (ans + v[i]) / 2;cout << ans << endl;return 0;
}

(欧拉通路/欧拉回路) A1126 Eulerian Path (25 分) 0.23

In graph theory, an Eulerian path is a path in a graph which visits every edge exactly once. Similarly, an Eulerian circuit is an Eulerian path which starts and ends on the same vertex. They were first discussed by Leonhard Euler while solving the famous Seven Bridges of Konigsberg problem in 1736. It has been proven that connected graphs with all vertices of even degree have an Eulerian circuit, and such graphs are called Eulerian. If there are exactly two vertices of odd degree, all Eulerian paths start at one of them and end at the other. A graph that has an Eulerian path but not an Eulerian circuit is called semi-Eulerian. (Cited from https://en.wikipedia.org/wiki/Eulerian_path)

Given an undirected graph, you are supposed to tell if it is Eulerian, semi-Eulerian, or non-Eulerian.

  • Input Specification:
    Each input file contains one test case. Each case starts with a line containing 2 numbers N (≤ 500), and M, which are the total number of vertices, and the number of edges, respectively. Then M lines follow, each describes an edge by giving the two ends of the edge (the vertices are numbered from 1 to N).
  • Output Specification:
    For each test case, first print in a line the degrees of the vertices in ascending order of their indices. Then in the next line print your conclusion about the graph – either Eulerian, Semi-Eulerian, or Non-Eulerian. Note that all the numbers in the first line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
  • Sample Input 1:
    7 12
    5 7
    1 2
    1 3
    2 3
    2 4
    3 4
    5 2
    7 6
    6 3
    4 5
    6 4
    5 6
    
  • Sample Output 1:
    2 4 4 4 4 4 2
    Eulerian
    
  • Sample Input 2:
    6 10
    1 2
    1 3
    2 3
    2 4
    3 4
    5 2
    6 3
    4 5
    6 4
    5 6
    
  • Sample Output 2:
    2 4 4 4 3 3
    Semi-Eulerian
    
  • Sample Input 3:
    5 8
    1 2
    2 5
    5 4
    4 1
    1 3
    3 2
    3 4
    5 3
    
  • Sample Output 3:
    3 3 4 3 3
    Non-Eulerian
    

题意:给出一个图,如果图连通,并且所有结点的度都是偶数,那么它就是Eulerian,如果处理两个结点的度是奇数其他都是偶数,那么它就是Semi-Eulerian,否则就是Non-Eulerian。
分析:邻接表存图,求出每个结点的度(在输入时完成),先判断图是否连通,再判断偶数度数的结点有多少个。

#include <bits/stdc++.h>
using namespace std;
const int maxv = 510;
vector<int> G[maxv], degree;
int vis[maxv] = {0};
int n, m, a, b, oddNum = 0, cnt = 0;
void dfs(int v) {vis[v] = true;cnt++;for (int i = 0; i < G[v].size(); i++) {int u = G[v][i];if (vis[u] == false) dfs(u); }
}
int main() { scanf("%d%d", &n, &m);degree.resize(n + 1, 0); //结点从1到N编号 for (int i = 0; i < m; i++) {scanf("%d%d", &a, &b);G[a].push_back(b);G[b].push_back(a);degree[a]++; degree[b]++; //两个结点的度+1 } for (int i = 1; i <= n; i++) {if (i > 1) printf(" ");if (degree[i] % 2 == 1) oddNum++;printf("%d", degree[i]);}printf("\n");dfs(1); if (oddNum == 0 && cnt == n) printf("Eulerian\n"); else if (oddNum == 2 && cnt == n) printf("Semi-Eulerian\n");else printf("Non-Eulerian\n"); //不是连通图  return 0;
}

(二叉树+后序中序建树+层次遍历) A1127 ZigZagging on a Tree (30 分) 0.49

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences. And it is a simple standard routine to print the numbers in level-order. However, if you think the problem is too simple, then you are too naive. This time you are supposed to print the numbers in “zigzagging order” – that is, starting from the root, print the numbers level-by-level, alternating between left to right and right to left. For example, for the following tree you must output: 1 11 5 8 17 12 20 15.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the inorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.
  • Output Specification:
    For each test case, print the zigzagging sequence of the tree in a line. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.
  • Sample Input:
    8
    12 11 20 17 1 15 8 5
    12 20 17 11 15 8 5 1
    
  • Sample Output:
    1 11 5 8 17 12 20 15
    

题意:给出一棵二叉树的后序和中序序列,然后之字形层次遍历二叉树。
思路:从后序和中序序列重建二叉树后进行层次遍历,每一层分开存储到vector数组中。输出时如果是偶数层,就从右往左输出,如果是奇数层,就从右往左输出。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50;
struct Node {int data, layer;Node* left, *right;
} node[maxn];vector<int> Post(maxn), In(maxn);
Node* Create(int r, int begin, int end) {if (begin > end) return NULL;Node *root = new Node;root->data = Post[r];root->left = root->right = NULL;int k = begin;while (k <= end && In[k] != Post[r]) k++;int numRight = end - k;root->left = Create(r - numRight - 1, begin, k - 1);root->right = Create(r - 1, k + 1, end); return root;
}
vector<int> ans, Level[50]; //每一个vector存储1层的结点
int maxLevel = 0;
void LevelOrder(Node *root) {root->layer = 0; queue<Node*> q;q.push(root);while (!q.empty()) {Node* e = q.front(); q.pop();if (e->layer > maxLevel) maxLevel = e->layer;Level[e->layer].push_back(e->data);if (e->left != NULL) {e->left->layer = e->layer + 1; q.push(e->left);}if (e->right != NULL) {e->right->layer = e->layer + 1; q.push(e->right);}}
}
int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d", &In[i]);for (int i = 0; i < n; i++) scanf("%d", &Post[i]);Node *tree = Create(n - 1, 0, n - 1);LevelOrder(tree);for (int i = 0; i <= maxLevel; i++) if (i % 2 == 1) for (int j = 0; j < Level[i].size(); j++) ans.push_back(Level[i][j]);else for (int j = Level[i].size() - 1; j >= 0; j--) ans.push_back(Level[i][j]);for (int i = 0; i < ans.size(); i++) {if (i > 0) printf(" ");printf("%d", ans[i]); }return 0;
}

(简单逻辑) A1128 N Queens Puzzle (20 分)

The “eight queens puzzle” is the problem of placing eight chess queens on an 8×8 chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens share the same row, column, or diagonal. The eight queens puzzle is an example of the more general N queens problem of placing N non-attacking queens on an N×N chessboard. (From Wikipedia - “Eight queens puzzle”.)

Here you are NOT asked to solve the puzzles. Instead, you are supposed to judge whether or not a given configuration of the chessboard is a solution. To simplify the representation of a chessboard, let us assume that no two queens will be placed in the same column. Then a configuration can be represented by a simple integer sequence (Q​1​​,Q​2​​,⋯,Q​N​​), where Q​i​​ is the row number of the queen in the i-th column. For example, Figure 1 can be represented by (4, 6, 8, 2, 7, 1, 3, 5) and it is indeed a solution to the 8 queens puzzle; while Figure 2 can be represented by (4, 6, 7, 2, 8, 1, 9, 5, 3) and is NOT a 9 queens’ solution.

  • Input Specification:
    Each input file contains several test cases. The first line gives an integer K (1<K≤200). Then K lines follow, each gives a configuration in the format “N Q​1​​ Q​2​​ … Q​N​​”, where 4≤N≤1000 and it is guaranteed that 1≤Q​i​​≤N for all i=1,⋯,N. The numbers are separated by spaces.
  • Output Specification:
    For each configuration, if it is a solution to the N queens problem, print YES in a line; or NO if not.
  • Sample Input:
    4
    8 4 6 8 2 7 1 3 5
    9 4 6 7 2 8 1 9 5 3
    6 1 5 2 6 4 3
    5 1 3 5 2 4
    
  • Sample Output:
    YES
    NO
    NO
    YES
    

题意:给出k个N皇后的解法序列,判断其是否是正确的。每个序列中的Qi分别是每一列皇后放置的行号。
思路:题目提及不会出现放在同一列的皇后,只需判断当前列的行号和之前列的行号是否为同一行,或者处在一条对角线上面

#include <bits/stdc++.h>
using namespace std;
int main() {int k, n;scanf("%d", &k);while (k--) {scanf("%d", &n);int row[n + 1] = {false}, flag = 1; //表示每一列的行号 for (int i = 1; i <= n; i++) scanf("%d", &row[i]);//不会用同样的列 for (int i = 1; i <= n; i++) {int curRow = row[i]; //表示第i列的行号/* 检查前面每列的行号, 如果前面有和这个在一行或者在对角线上的 */ for (int j = 1; j < i; j++) {int offRow = row[j]; if (curRow == offRow || abs(i - j) == abs(curRow - offRow)) {printf("NO\n");flag = 0; break;} }if (flag == 0) break;} if (flag) printf("YES\n");}return 0;
}

(STL, set自定义排序规则) A1129 Recommendation System (25 分) 0.34

Recommendation system predicts the preference that a user would give to an item. Now you are asked to program a very simple recommendation system that rates the user’s preference by the number of times that an item has been accessed by this user.

  • Input Specification:
    Each input file contains one test case. For each test case, the first line contains two positive integers: N (≤ 50,000), the total number of queries, and K (≤ 10), the maximum number of recommendations the system must show to the user. Then given in the second line are the indices of items that the user is accessing – for the sake of simplicity, all the items are indexed from 1 to N. All the numbers in a line are separated by a space.

  • Output Specification:
    For each case, process the queries one by one. Output the recommendations for each query in a line in the format:

    query: rec[1] rec[2] ... rec[K]
    

    where query is the item that the user is accessing, and rec[i] (i=1, … K) is the i-th item that the system recommends to the user. The first K items that have been accessed most frequently are supposed to be recommended in non-increasing order of their frequencies. If there is a tie, the items will be ordered by their indices in increasing order.

    Note: there is no output for the first item since it is impossible to give any recommendation at the time. It is guaranteed to have the output for at least one query.

  • Sample Input:

    12 3
    3 5 7 5 5 3 2 1 8 3 8 12
    
  • Sample Output:

    5: 3
    7: 3 5
    5: 3 5 7
    5: 5 3 7
    3: 5 3 7
    2: 5 3 7
    1: 5 3 2
    8: 5 3 1
    3: 5 3 1
    8: 3 5 1
    12: 3 5 8
    

题意:根据用户每次点击的东西的编号,输出他在点击当前编号之前应该给这个用户推荐的商品的编号,只推荐k个,也就是输出用户曾经点击过的商品编号的最多的前k个。如果恰好两个商品有相同的点击次数,就输出编号较小的那个。

思路:因为每个商品有两个属性:编号value和出现的次数cnt,编号具有唯一性,然后set又会根据大小自动排序,所以我们可以将value和cnt组成一个node属性,把所有商品编号和它对应的次数变成node放入set里面,重载小于号,使<根据set中node的cnt排序,如果cnt相等就按照node的value排序。这样set里面就是按照出现次数排序好的商品node,每次输出set的前k个node的value值就可以。

book[query]标记num出现的次数,每次寻找set中当前值为query和次数为book[query]的那个值,如果找到了了就把他移除, 然后将book[query]+1,在将node(query, book[query])插入到set中,set会帮忙根据我们自定义的<的规则自动排序

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50010;
int book[maxn] = {0};
struct item {int value, cnt; //编号 查询次数bool operator < (const item &a) const {return (cnt != a.cnt) ? cnt > a.cnt : value < a.value;}
};
int main() {int n, k, query;scanf("%d%d", &n, &k);set<item> s;for (int i = 0; i < n; i++) {scanf("%d", &query);if (i != 0) {printf("%d:", query);int tempcnt = 0;for (auto it = s.begin(); tempcnt < k && it != s.end(); it++) {printf(" %d", it->value);tempcnt++;} printf("\n");}auto it = s.find(item{query, book[query]});if (it != s.end()) s.erase(it);book[query]++;s.insert(item{query, book[query]});}return 0;
}

(简单数学) A1132 Cut Integer (20 分) 0.63

Cutting an integer means to cut a K digits lone integer Z into two integers of (K/2) digits long integers A and B. For example, after cutting Z = 167334, we have A = 167 and B = 334. It is interesting to see that Z can be devided by the product of A and B, as 167334 / (167 × 334) = 3. Given an integer Z, you are supposed to test if it is such an integer.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤ 20). Then N lines follow, each gives an integer Z (10 ≤ Z <2​31​​). It is guaranteed that the number of digits of Z is an even number.
  • Output Specification:
    For each case, print a single line Yes if it is such a number, or No if not.
  • Sample Input:
    3
    167334
    2333
    12345678
    
  • Sample Output:
    Yes
    No
    

这题比较简单,但是需要注意的是,分开的两个可能存在0,如10会分成1和0,不检查就会导致浮点错误,后两个测试点错误。

#include <bits/stdc++.h>
using namespace std;
int main() {int n;scanf("%d", &n);while (n--) {string s; cin >> s;int k = s.size() / 2, t, t1, t2;t = stoi(s), t1 = stoi(s.substr(0, k)), t2 = stoi(s.substr(k, k));if (t1 * t2 != 0 && t % (t1 * t2) == 0) printf("Yes\n");else printf("No\n");}return 0;
}

(静态链表) A1133 Splitting A Linked List (25 分) 0.32

乙级的题目,链表元素分类。先遍历整个链表,得到所有有效结点,然后分段分类入容器中,最后打印出来即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
struct Node {int addr, data, next;
} ori[maxn];
vector<Node> v, ans; int main() {int first, n, k, addr, d, next;scanf("%d%d%d", &first, &n, &k);for (int i = 0; i < n; i++) {scanf("%d%d%d", &addr, &d, &next);ori[addr] = {addr, d, next};} for (int i = first; i != -1; i = ori[i].next)  v.push_back(ori[i]); for (int i = 0; i < v.size(); i++) //存入小于0的数 if (v[i].data < 0) ans.push_back(v[i]);for (int i = 0; i < v.size(); i++) //存入大于等于0小于等于k的数 if (v[i].data >= 0 && v[i].data <= k) ans.push_back(v[i]);for (int i = 0; i < v.size(); i++) //存入大于k的数 if (v[i].data > k) ans.push_back(v[i]);for (int i = 0; i < ans.size() - 1; i++) printf("%05d %d %05d\n", ans[i].addr, ans[i].data, ans[i + 1].addr);printf("%05d %d -1\n", ans[ans.size() - 1].addr, ans[ans.size() - 1].data);return 0;
}

(哈希散列+图的顶点覆盖) A1134 Vertex Cover (25 分)

A vertex cover of a graph is a set of vertices such that each edge of the graph is incident to at least one vertex of the set. Now given a graph with several vertex sets, you are supposed to tell if each of them is a vertex cover or not.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers N and M (both no more than 10​4​​), being the total numbers of vertices and the edges, respectively. Then M lines follow, each describes an edge by giving the indices (from 0 to N−1) of the two ends of the edge.

    After the graph, a positive integer K (≤ 100) is given, which is the number of queries. Then K lines of queries follow, each in the format:

    N​v​​ v[1] v[2]⋯v[N​v​​]
    

    where N​v​​ is the number of vertices in the set, and v[i]'s are the indices of the vertices.

  • Output Specification:
    For each query, print in a line Yes if the set is a vertex cover, or No if not.

  • Sample Input:

    10 11
    8 7
    6 8
    4 5
    8 4
    8 1
    1 2
    1 4
    9 8
    9 1
    1 0
    2 4
    5
    4 0 3 8 4
    6 6 1 7 5 4 9
    3 1 8 4
    2 2 8
    7 9 8 7 6 5 4 2
    
  • Sample Output:

    No
    Yes
    Yes
    No
    No
    

题意:给出n个结点和m条边,再给出k个集合,对k个集合逐个进行判断,每个集合里面都是结点编号,如果这个集合中存在整个图中所有边的至少一端的端点,就是vertex cover。这个题目最大的困难就是看懂题目,懂了就简单了。我一开始也没有看懂。

vertex cover的问题定义:
实例:图G=(V,E)
问题:是否存在V的子集V',使得|V'|<=|V|,并且G中的每条边e,至少有一个顶点在V'中

#include <bits/stdc++.h>
using namespace std;int main() {int n, m, k, nv, a, b, num;scanf("%d%d", &n, &m);vector<int> v[n];for (int i = 0; i < m; i++) {scanf("%d%d", &a, &b);v[a].push_back(i);v[b].push_back(i); //保存每个结点属于的每条边的编号}scanf("%d", &k);for (int i = 0; i < k; i++) {scanf("%d", &nv);int flag = 0;vector<int> Hash(m, 0);for (int j = 0; j < nv; j++) {scanf("%d", &num);for (int t = 0; t < v[num].size(); t++) {Hash[v[num][t]] = 1; //将当前元素属于的所有边的编号的hash标记为1}}for (int j = 0; j < m; j++) {if (Hash[j] == 0) { //如果hash数组中有元素为0, 说明有边没有被集合S涉及到printf("No\n"); flag = 1; break;}}if (flag == 0) printf("Yes\n");}
}

(红黑树判断) A1135 Is It A Red-Black Tree (30 分)

There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties:

(1) Every node is either red or black.
(2) The root is black.
(3) Every leaf (NULL) is black.
(4) If a node is red, then both its children are black.
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

For example, the tree in Figure 1 is a red-black tree, while the ones in Figure 2 and 3 are not. For each given binary search tree, you are supposed to tell if it is a legal red-black tree.

  • Input Specification:
    Each input file contains several test cases. The first line gives a positive integer K (≤30) 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 tree. The second line gives the preorder traversal sequence of the tree. While all the keys in a tree are positive integers, we use negative signs to represent red nodes. All the numbers in a line are separated by a space. The sample input cases correspond to the trees shown in Figure 1, 2 and 3.
  • Output Specification:
    For each test case, print in a line “Yes” if the given tree is a red-black tree, or “No” if not.
  • Sample Input:
    3
    9
    7 -2 1 5 -4 -11 8 14 -15
    9
    11 -2 1 -7 5 -4 8 14 -15
    8
    10 -7 5 -6 8 15 -11 17
    
  • Sample Output:
    Yes
    No
    No
    
#include <bits/stdc++.h>
using namespace std;
vector<int> arr;
struct node {int val;node *left, *right;
};
/* 给出一棵二叉搜索树的前序遍历(插入序列), 判断它是否是一棵合法的红黑树 */
/* 根据先序序列直接建树 */
void insert(node *&root, int v) {if (root == NULL) {root = new node;root->val = v;root->left = root->right = NULL;return;}if (abs(v) <= abs(root->val)) insert(root->left, v);else insert(root->right, v);
}
/* 根据建立的树, 从根结点开始遍历, 如果为空树, true; 如果为红色, 判断孩子结点是否都是黑色*/
bool judge1(node *root) {if (root == NULL) return true; //叶子结点为黑色 if (root->val < 0) { //红色结点的孩子必须都是黑色 if (root->left != NULL && root->left->val < 0) return false;if (root->right != NULL && root->right->val < 0) return false;}return judge1(root->left) && judge1(root->right);
}
/* 从每个子树的根结点开始, 递归遍历, 检查左子树的高度和右子树的
高度(这里高度指黑色结点的个数) */
int getNum(node *root) {if (root == NULL) return 0;int l = getNum(root->left), r = getNum(root->right);return root->val > 0 ? max(l, r) + 1 : max(l, r);
}
/* 从根结点开始, 递归遍历, 检查每个结点的左子树和右子树高度, 比较是否相等 */
bool judge2(node *root) {if (root == NULL) return true;int l = getNum(root->left), r = getNum(root->right);if (l != r) return false;return judge2(root->left) && judge2(root->right);
}
int main() {int k, n;scanf("%d", &k);for (int i = 0; i < k; i++) {scanf("%d", &n);arr.resize(n);node *root = NULL;for (int j = 0; j < n; j++) {scanf("%d", &arr[j]);insert(root, arr[j]); } /* 判断根结点是否是黑色 */ if (arr[0] < 0 || judge1(root) == false || judge2(root) == false) printf("No\n");else printf("Yes\n"); }return 0;
}

(字符串操作) A1136 A Delayed Palindrome (20 分) 0.31

乙级做过的题,B1079 延迟的回文数 (20 分),可以和那边一样使用大整数模板,不过这里不值得为20分写这么长的代码。

#include <bits/stdc++.h>
using namespace std;
string rev(string s) { //逆转字符串reverse(s.begin(), s.end());return s;
}
string add(string s1, string s2) { string s = s1; //字符串和它的倒置相加, 只需从尾到头相加, 再处理最后一个进位int carry = 0;for (int i = s1.length() - 1; i >= 0; i--) { s[i] = (s1[i] - '0' + s2[i] - '0' + carry) % 10 + '0';carry = (s1[i] - '0' + s2[i] - '0' + carry) / 10;}if (carry > 0) s = "1" + s;return s;
}
int main() {string s, t, sum;cin >> s;t = rev(s);if (s == t) { //用字符串的特性来判断是否是回文串cout << s << " is a palindromic number.\n";return 0;}for (int i = 0; i < 10; i++) {sum = add(s, t);cout << s << " + " << t << " = " << sum << endl;if (sum == rev(sum)) {cout << sum << " is a palindromic number.\n";return 0;}s = sum, t = rev(sum);}cout << "Not found in 10 iterations.\n";return 0;
}

(排序+复杂模拟+map) A1137 Final Grading (25 分) 0.26

乙级做过的题目。这里使用map提供由字符串到vector中序号+1的映射,用0表示不存在,是一种很方便的思路。

#include <bits/stdc++.h>
using namespace std;
struct student {string name;int gp, gm, gf, g; //在线编程成绩 期中考试成绩 期末考试成绩 总评
};
bool cmp(student a, student b) { //输出顺序为按照总评分数递减; 若有并列,则按学号递增return a.g != b.g ? a.g > b.g : a.name < b.name; //string可以直接比较大小
}
map<string, int> idx; //记录学生姓名和序号的映射
int main() {int p, n, m, score, cnt = 1;scanf("%d%d%d", &p, &n, &m);vector<student> v, ans; //合为一张的成绩单 获得合格证书的学生名单string s; for (int i = 0; i < p; i++) {cin >> s >> score; if (score >= 200) { //所有人必须要编程>=200分v.push_back(student{s, score, -1, -1, 0}); //有的成绩不存在则表示为-1 idx[s] = cnt++; //不然不记录后面的成绩}}for (int i = 0; i < m; i++) {cin >> s >> score; if (idx[s] != 0) v[idx[s] - 1].gm = score; }for (int i = 0; i < n; i++) {cin >> s >> score;if (idx[s] != 0) {int temp = idx[s] - 1;v[temp].gf = v[temp].g = score;  //总评分数(四舍五入精确到整数)if (v[temp].gm > v[temp].gf) v[temp].g = int(round(v[temp].gm * 0.4 + v[temp].gf * 0.6));}}for (int i = 0; i < v.size(); i++)  //总评获得不少于60分if (v[i].g >= 60) ans.push_back(v[i]); sort(ans.begin(), ans.end(), cmp);for (int i = 0; i < ans.size(); i++)  //至少存在1个合格的学生printf("%s %d %d %d %d\n", ans[i].name.c_str(), ans[i].gp, ans[i].gm, ans[i].gf, ans[i].g);return 0;
}

(二叉树+先序中序->后序) A1138 Postorder Traversal (25 分) 0.44

Suppose that all the keys in a binary tree are distinct positive integers. Given the preorder and inorder traversal sequences, you are supposed to output the first number of the postorder traversal sequence of the corresponding binary tree.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤ 50,000), the total number of nodes in the binary tree. The second line gives the preorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.
  • Output Specification:
    For each test case, print in one line the first number of the postorder traversal sequence of the corresponding binary tree.
  • Sample Input:
    7
    1 2 3 4 5 6 7
    2 3 1 5 4 7 6
    
  • Sample Output:
    3
    

题意:给出一棵二叉树的先序和中序遍历序列,输出后序遍历序列的第一个数。套板子的题目。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50010;
int Pre[maxn], In[maxn], num = 0;
vector<int> Post;void getPost(int root, int begin, int end) {if (begin > end) return;int k = begin;while (k <= end && In[k] != Pre[root]) k++;int numLeft = k - begin;getPost(root + 1, begin, k - 1); //递归访问左子树 getPost(root + numLeft + 1, k + 1, end); //递归访问右子树 Post.push_back(Pre[root]); //访问到右子树最深处, 得到后序序列元素
} int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d", &Pre[i]);for (int i = 0; i < n; i++) scanf("%d", &In[i]);getPost(0, 0, n - 1); //从先序和中序推出后序序列printf("%d\n", Post[0]);return 0;
}

(模拟+STL应用) A1139 First Contact (30 分)

Unlike in nowadays, the way that boys and girls expressing their feelings of love was quite subtle in the early years. When a boy A had a crush on a girl B, he would usually not contact her directly in the first place. Instead, he might ask another boy C, one of his close friends, to ask another girl D, who was a friend of both B and C, to send a message to B – quite a long shot, isn’t it? Girls would do analogously.

Here given a network of friendship relations, you are supposed to help a boy or a girl to list all their friends who can possibly help them making the first contact.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers N (1 < N ≤ 300) and M, being the total number of people and the number of friendship relations, respectively. Then M lines follow, each gives a pair of friends. Here a person is represented by a 4-digit ID. To tell their genders, we use a negative sign to represent girls.

    After the relations, a positive integer K (≤ 100) is given, which is the number of queries. Then K lines of queries follow, each gives a pair of lovers, separated by a space. It is assumed that the first one is having a crush on the second one.

  • Output Specification:
    For each query, first print in a line the number of different pairs of friends they can find to help them, then in each line print the IDs of a pair of friends.
    If the lovers A and B are of opposite genders, you must first print the friend of A who is of the same gender of A, then the friend of B, who is of the same gender of B. If they are of the same gender, then both friends must be in the same gender as theirs. It is guaranteed that each person has only one gender.
    The friends must be printed in non-decreasing order of the first IDs, and for the same first ones, in increasing order of the seconds ones.

  • Sample Input:

    10 18
    -2001 1001
    -2002 -2001
    1004 1001
    -2004 -2001
    -2003 1005
    1005 -2001
    1001 -2003
    1002 1001
    1002 -2004
    -2004 1001
    1003 -2002
    -2003 1003
    1004 -2002
    -2001 -2003
    1001 1003
    1003 -2001
    1002 -2001
    -2002 -2003
    5
    1001 -2001
    -2003 1001
    1005 -2001
    -2002 -2004
    1111 -2003
    
  • Sample Output:

    4
    1002 2004
    1003 2002
    1003 2003
    1004 2002
    4
    2001 1002
    2001 1003
    2002 1003
    2002 1004
    0
    1
    2003 2001
    0
    

题意:给出一份朋友名单,ID为4位数,负数为女性。然后给出多对查询,寻找A的同性友人C和B的同性友人D,C和D互为朋友,可以帮助A和B第一次接触。

#include <bits/stdc++.h>
using namespace std;
struct node {int a, b;
};
unordered_map<int, bool> arr;
bool cmp(node x, node y) {return x.a != y.a ? x.a < y.a : x.b < y.b;
}
int main() {int n, m, k;scanf("%d%d", &n, &m);vector<int> v[10000];for (int i = 0; i < m; i++) {string a, b;cin >> a >> b;if (a.length() == b.length()) { //分别存储所有人的同性朋友 v[abs(stoi(a))].push_back(abs(stoi(b)));v[abs(stoi(b))].push_back(abs(stoi(a)));}   //标记两个人是朋友 arr[abs(stoi(a)) * 10000 + abs(stoi(b))] = arr[abs(stoi(b)) * 10000 + abs(stoi(a))] = true; }scanf("%d", &k);for (int i = 0; i < k; i++) {int a, b; cin >> a >> b;vector<node> ans; //对于一对想要在一起的A和B,他们需要for (int j = 0; j < v[abs(a)].size(); j++) { //先找A的所有同性朋友C for (int k = 0; k < v[abs(b)].size(); k++) { //找B的所有同性朋友D //A在寻找同性朋友时,需要避免找到他想要的伴侣B,所以当当前朋友就是B;//或者B的同性朋友就是A时, 舍弃该结果if (v[abs(a)][j] == abs(b) || abs(a) == v[abs(b)][k]) continue;//当C和D两人是朋友的时候则可以输出C和Dif (arr[v[abs(a)][j] * 10000 + v[abs(b)][k]] == true) ans.push_back(node{v[abs(a)][j], v[abs(b)][k]});}}sort(ans.begin(), ans.end(), cmp);printf("%d\n", int(ans.size()));for(int j = 0; j < ans.size(); j++)printf("%04d %04d\n", ans[j].a, ans[j].b);}return 0;
}

(字符串操作) A1140 Look-and-say Sequence (20 分) 0.46

乙级B1084 外观数列 (20 分),做过的题目。但是这样写太麻烦了,虽然运行速度快。

#include <bits/stdc++.h>
const int maxn = 200000;
char ans[maxn], changed[maxn];
int len = 0;
int main() {int n, d;scanf("%d%d", &d, &n);if (n == 1) printf("%d", d);else if (n == 2) printf("%d1", d);else {changed[0] = d + '0'; changed[1] = '1'; changed[2] = '\0';for (int i = 3; i <= n; i++) {  //从第三项开始 for (int j = 0; changed[j]; ) {char t = changed[j]; int k = 0;while (changed[j + k] && changed[j + k] == t) k++;ans[len++] = t;ans[len++] = k + '0'; //k代表一个字符重复的次数 j += k; //移动到下一个重复出现的字符 }ans[len] = '\0';if (i < n) {strcpy(changed, ans); len = 0;}}printf("%s", ans);       }return 0;
}

用string,大大提高编码速度,考场上这才是重要的。仔细观察可以有下面的代码:

#include <bits/stdc++.h>
using namespace std;
int main() {int n, j;string s;cin >> s >> n;for (int cnt = 1; cnt < n; cnt++) {string t;for (int i = 0; i < s.length(); i = j) { //一次循环后i跳到j的位置//后面的字符与前面i所在的字符相同, j就不断后移for (j = i; j < s.length() && s[j] == s[i]; j++);t += to_string((s[i] - '0') * 10 + j - i); //j-i就是出现的次数}s = t; }cout << s; //输出结果return 0;
}

(LCA+BST) A1143 Lowest Common Ancestor (30 分) 0.23

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

A binary search tree (BST) is recursively defined as a binary tree which has the following properties:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
Both the left and right subtrees must also be binary search trees.

Given any two nodes in a BST, you are supposed to find their LCA.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the BST, respectively. In the second line, N distinct integers are given as the preorder traversal sequence of the BST. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.
  • Output Specification:
    For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the BST, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..
  • Sample Input:
    6 8
    6 3 1 2 5 4 8 7
    2 5
    8 7
    1 9
    12 -3
    0 8
    99 99
    
  • Sample Output:
    LCA of 2 and 5 is 3.
    8 is an ancestor of 7.
    ERROR: 9 is not found.
    ERROR: 12 and -3 are not found.
    ERROR: 0 is not found.
    ERROR: 99 and 99 are not found.
    

题目大意:给出一棵二叉搜索树的前序遍历,问结点u和v的共同最低祖先是谁。

分析:map<int, bool> mp用来标记树中所有出现过的结点,遍历一遍pre数组,将当前结点标记为a,
如果u和v分别在a的左、右,或者u、v其中一个就是当前a,即(a >= u && a <= v) || (a >= v && a <= u),
说明找到了这个共同最低祖先a,退出当前循环~最后根据要求输出结果即可。

#include <bits/stdc++.h>
using namespace std;
map<int, bool> mp;
int main() {int m, n, u, v, a;scanf("%d %d", &m, &n);vector<int> pre(n);for (int i = 0; i < n; i++) {scanf("%d", &pre[i]);mp[pre[i]] = true;}for (int i = 0; i < m; i++) {scanf("%d %d", &u, &v);for(int j = 0; j < n; j++) {a = pre[j];if ((a >= u && a <= v) || (a >= v && a <= u)) break;}if (mp[u] == false && mp[v] == false)printf("ERROR: %d and %d are not found.\n", u, v);else if (mp[u] == false || mp[v] == false)printf("ERROR: %d is not found.\n", mp[u] == false ? u : v);else if (a == u || a == v)printf("%d is an ancestor of %d.\n", a, a == u ? v : u);elseprintf("LCA of %d and %d is %d.\n", u, v, a);}return 0;
}

(简单模拟+STL) A1144 The Missing Number (20 分) 0.28

Given N integers, you are supposed to find the smallest positive integer that is NOT in the given list.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (≤10​5​​). Then N integers are given in the next line, separated by spaces. All the numbers are in the range of int.
  • Output Specification:
    Print in a line the smallest positive integer that is missing from the input list.
  • Sample Input:
    10
    5 -25 9 6 1 3 4 2 5 17
    
  • Sample Output:
    7
    

题意:给出一个N个数字的集合,求出没有在集合中出现的最小的正整数。下面这样写还是麻烦了一点。更好的是用map,每输入一个数字其出现的次数就加一,然后从1开始,找到没有出现过的数字就可以了。

#include <bits/stdc++.h>
using namespace std;
set<int> s;
int main() {int n, t;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &t);if (t < 0) continue; //不记录负数else s.insert(t);}if (s.size() == 0) printf("1\n");else {int index = 1; //从1开始的标尺for (auto it : s) {if (it == index) index++;else {printf("%d", index);return 0;}}printf("%d", index); //全部符合就输出此时的index}return 0;
}

(拓扑排序+判断拓扑序列正误) A1146 Topological Order (25 分)

This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topological order obtained from the given directed graph? Now you are supposed to write a program to test each of the options.

- Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 1,000), the number of vertices in the graph, and M (≤ 10,000), the number of directed edges. Then M lines follow, each gives the start and the end vertices of an edge. The vertices are numbered from 1 to N. After the graph, there is another positive integer K (≤ 100). Then K lines of query follow, each gives a permutation of all the vertices. All the numbers in a line are separated by a space.

  • Output Specification:
    Print in a line all the indices of queries which correspond to “NOT a topological order”. The indices start from zero. All the numbers are separated by a space, and there must no extra space at the beginning or the end of the line. It is graranteed that there is at least one answer.
  • Sample Input:
    6 8
    1 2
    1 3
    5 2
    5 4
    2 3
    2 6
    3 4
    6 4
    5
    1 5 2 3 6 4
    5 1 2 6 3 4
    5 1 2 3 6 4
    5 2 1 6 3 4
    1 2 3 4 5 6
    
  • Sample Output:
    3 4
    

题意:给出一个有向图,判断给定序列是否是拓扑序列。因为题目保证该图可以拓扑排序,因此该图必定是有向无环图(DAG),不会出现所有拓扑序列都是错误的情况。

思路:用邻接表存储这个有向图,并在输入时预先处理好入度数组及其备份数组。然后从头遍历每一个拓扑序列,遇到当前结点入度不为0则其不是拓扑序列;如果当前结点为0,则将它所指向的所有结点的入度-1。另外,记得还原入度数组

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
vector<int> G[maxn];
int main() {int n, m, u, v;scanf("%d%d", &n, &m);int indegree[n + 1], temp[n + 1];memset(indegree, 0, sizeof(indegree));memset(temp, 0, sizeof(temp));for (int i = 0; i < m; i++) {scanf("%d%d", &u, &v); //起点, 终点 G[u].push_back(v);indegree[v]++; //u->v, v的入度加1 temp[v]++; //备用数组 }int k, topo, num = 0;set<int> ans;scanf("%d", &k); for (int i = 0; i < k; i++) {for (int j = 0; j < n; j++) {scanf("%d", &topo);if (indegree[topo] == 0) {for (int v = 0; v < G[topo].size(); v++) indegree[G[topo][v]]--; continue;}else ans.insert(i); //发现该序列非拓扑排序 } //还原入度数组for (int h = 1; h <= n; h++) indegree[h] = temp[h];} for (auto it : ans) {if (num++ > 0) printf(" ");printf("%d", it);}return 0;
}

(大小堆判断+完全二叉树后序遍历) A1147 Heaps (30 分) 0.41

In computer science, a heap is a specialized tree-based data structure that satisfies the heap property: if P is a parent node of C, then the key (the value) of P is either greater than or equal to (in a max heap) or less than or equal to (in a min heap) the key of C. A common implementation of a heap is the binary heap, in which the tree is a complete binary tree. (Quoted from Wikipedia at https://en.wikipedia.org/wiki/Heap_(data_structure))
Your job is to tell if a given complete binary tree is a heap.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 100), the number of trees to be tested; and N (1 < N ≤ 1,000), the number of keys in each tree, respectively. Then M lines follow, each contains N distinct integer keys (all in the range of int), which gives the level order traversal sequence of a complete binary tree.
  • Output Specification:
    For each given tree, print in a line Max Heap if it is a max heap, or Min Heap for a min heap, or Not Heap if it is not a heap at all. Then in the next line print the tree’s postorder traversal sequence. All the numbers are separated by a space, and there must no extra space at the beginning or the end of the line.
  • Sample Input:
    3 8
    98 72 86 60 65 12 23 50
    8 38 25 58 52 82 70 60
    10 28 15 12 34 9 8 56
    
  • Sample Output:
    Max Heap
    50 60 65 72 12 23 86 98
    Min Heap
    60 58 52 38 82 70 25 8
    Not Heap
    56 12 34 28 9 8 15 10
    

题意:给出一棵完全二叉树的层序遍历序列,判断这棵完全二叉树是大顶堆还是小顶堆或者不是堆,然后打印这棵树的后序遍历序列。
思路:题目说得很清楚。堆是基于树的满足堆序性的数据结构,其中每个父结点的值要么都大于或等于子结点(大顶堆),要么都小于子结点(小顶堆)。因此,我们可以根据层次序列,从1到N/2,对所有有孩子的结点判断它们的孩子是不是满足要求
步骤:

  • 首先根据a[1]和a[2]的大小比较判断 猜测是大顶(flag=1)还是小顶(flag=0);
  • 从1到N/2,依次判断每个结点是否满足要求,只要有一个结点不满足要求就flag=-1,表示不是堆;
  • 接着后序遍历完全二叉树,输出后序序列。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int num = 0, m, n, a[maxn];
void Postorder(int root) {if (root <= n) {Postorder(root * 2);Postorder(root * 2 + 1);printf("%d%s", a[root], root == 1 ? "\n" : " "); //是最后的根(第一个)就换行 }
}
int main() {scanf("%d%d", &m, &n);while (m--) {for (int i = 1; i <= n; i++) scanf("%d", &a[i]); //根从1开始int flag = a[1] > a[2] ? 1 : 0; //大顶堆或者小顶堆for (int i = 1; i <= n / 2; i++) {int left = i * 2, right = i * 2 + 1; //左右儿子if (flag == 1 && (a[i] < a[left] || (right <= n && a[i] < a[right]))) flag = -1;if (flag == 0 && (a[i] > a[left] || (right <= n && a[i] > a[right]))) flag = -1;}if (flag == -1) printf("Not Heap\n");else printf("%s Heap\n", flag == 1 ? "Max" : "Min");Postorder(1);}return 0;
}

(逻辑题) A1148 Werewolf - Simple Version (20 分)

本题是这个问题的升级版:已知 N 名玩家中有2人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?

  • 输入格式:
    输入在第一行中给出一个正整数 N(5≤N≤100)。随后 N 行,第 i 行给出第 i 号玩家说的话(1≤i≤N),即一个玩家编号,用正号表示好人,负号表示狼人。
  • 输出格式:
    如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A=a[1],…,a[M] 和 B=b[1],…,b[M],若存在 0≤k<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],则称序列 A 小于序列 B。若无解则输出 No Solution
  • 输入样例 1:
    5
    -2
    +3
    -4
    +5
    +4
    
  • 输出样例 1:
    1 4
    
  • 输入样例 2:
    6
    +6
    +3
    +1
    -5
    -2
    +4
    
  • 输出样例 2(解不唯一):
    1 5
    
  • 输入样例 3:
    5
    -2
    -3
    -4
    -5
    -1
    
  • 输出样例 3:
    No Solution
    

从题目中可以得到以下几个事实:

  1. 狼人只有两个;
  2. 说谎者只有两个,一个是狼人,一个是好人。

因为题目要求的是谁是狼人(而不是谁说了谎),所以假设枚举的这两个人都是狼人,如果可以推出一组解完美符合以上两个事实(从条件1推出条件2),就可以打印并退出了,没有就No Solution。

如果假设这里枚举的两个人都是说谎者(更适合求谁说谎的题目),那么本题对狼人的判断条件会复杂一点,还要找出说谎者中谁是狼人。不过也差不多。

#include <bits/stdc++.h>
using namespace std;
/* 有且只有两个狼人, 其中有一个狼人说谎;
有且只有两个人说谎, 一个是狼人, 一个是好人 */
int main() {int n, a[110]; scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%d", &a[i]);for (int i = 1; i <= n; i++) {for (int j = i + 1; j <= n; j++) {vector<int> good(n + 1, 1); //1是好人, -1是狼人 good[i] = good[j] = -1; //枚举两个狼人vector<int> lie; //看看谁说谎, 先假设v数组所有人说的都是对的 //然后对比v数组和a数组, 某人说别人是好人, 别人在这里恰好是好人, 就没说谎//不然, 说别人是狼人而实际是好人, 说别人是好人而实际是狼人, 就说谎了for (int k = 1; k <= n; k++) if (a[k] * good[abs(a[k])] < 0) lie.push_back(k); //说得话与对应的人不一致//说谎的人只有两个, 一个是狼人一个是好人, 就找到了第一组解 if (lie.size() == 2 && good[lie[0]] + good[lie[1]] == 0) {cout << i << " " << j;return 0;} } }cout << "No Solution";return 0;
}

(STL的使用) A1149 Dangerous Goods Packaging (25 分) 0.38

乙级做过的题目。

#include <bits/stdc++.h>
using namespace std;
typedef set<int>::iterator sT;
map<int, set<int> > inc;
int main() {int n, m, g1, g2, k;scanf("%d%d", &n, &m);for (int i = 0; i < n; i++) {scanf("%d%d", &g1, &g2);inc[g1].insert(g2);inc[g2].insert(g1);}while (m--) {set<int> goods;scanf("%d", &k);for (int i = 0; i < k; i++) {scanf("%d", &g1);goods.insert(g1);}int flag = 0;for (auto it : goods) {if (inc[it].size() == 0) continue; //这个物品没有不相容物for (auto it2 : inc[it]) {sT check = goods.find(it2);if (check != goods.end()) { //有不相容物并且在船上printf("No\n");flag = 1; break;}}if (flag) break;}if (!flag) printf("Yes\n"); //没有任何违禁品}return 0;
}

(LCA+二叉树遍历+先序/中序) A1151 LCA in a Binary Tree (30 分) 0.26

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.
  • Output Specification:
    For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found…
  • Sample Input:
    6 8
    7 2 3 4 6 5 1 8
    5 3 7 2 6 4 8 1
    2 6
    8 1
    7 9
    12 -3
    0 8
    99 99
    
  • Sample Output:
    LCA of 2 and 6 is 3.
    8 is an ancestor of 1.
    ERROR: 9 is not found.
    ERROR: 12 and -3 are not found.
    ERROR: 0 is not found.
    ERROR: 99 and 99 are not found.
    

题目大意:给出中序序列和先序序列,再给出两个点,求这两个点的最近公共祖先。

分析:不用建树。已知某个树的根结点,若a和b在根结点的左边,则a和b的最近公共祖先在当前子树根结点的左子树寻找;如果a和b在当前子树根结点的两边,在当前子树的根结点就是a和b的最近公共祖先,如果a和b在当前子树根结点的右边,则a和b的最近公共祖先就在当前子树的右子树寻找。

中序加先序可以唯一确定一棵树,在不构建树的情况下,在每一层的递归中,可以得到树的根结点,在此
并入lca算法可以确定两个结点的公共祖先

#include <bits/stdc++.h>
using namespace std;
map<int, int> pos;
vector<int> in, pre;
void lca(int inl, int inr, int preRoot, int a, int b) {if (inl > inr) return;int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn = pos[b];if (aIn < inRoot && bIn < inRoot) lca(inl, inRoot - 1, preRoot + 1, a, b);else if ((aIn < inRoot && bIn > inRoot) || (aIn > inRoot && bIn < inRoot))printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);else if (aIn > inRoot && bIn > inRoot) lca(inRoot + 1, inr, preRoot + 1 + (inRoot - inl), a, b);else if (aIn == inRoot) printf("%d is an ancestor of %d.\n", a, b);else if (bIn == inRoot) printf("%d is an ancestor of %d.\n", b, a);
}
int main() {int m, n, a, b;scanf("%d%d", &m, &n);in.resize(n + 1); pre.resize(n + 1);for (int i = 1; i <= n; i++) {scanf("%d", &in[i]);pos[in[i]] = i;}for (int i = 1; i <= n; i++) scanf("%d", &pre[i]);for (int i = 0; i < m; i++) {scanf("%d%d", &a, &b);if (pos[a] == 0 && pos[b] == 0) printf("ERROR: %d and %d are not found.\n", a, b);else if (pos[a] == 0 || pos[b] == 0) printf("ERROR: %d is not found.\n", pos[a] == 0 ? a : b);else lca(1, n, 1, a, b);}return 0;
}

(字符串处理) A1152 Google Recruitment (20 分) 0.24

乙级的题目,谷歌招聘。K<10,不会溢出。要小心的是素数字符串的前导零也要输出。然后下面是string提供的字符串与数值间的类型转换函数。本题用到的是stoi。

#include <bits/stdc++.h>
using namespace std;
bool isPrime(int n) {if (n <= 1) return false;int sqr = (int)sqrt(1.0 * n);for (int i = 2; i <= sqr; i++) if (n % i == 0) return false;return true;
}
int main() {int L, K; //L<=1000, K<10 string s; cin >> L >> K >> s;for (int i = 0; i <= L - K; i++) {string t = s.substr(i, K); int num = stoi(t);if (isPrime(num)) {cout << t << endl;return 0;} }cout << "404\n";return 0;
}

(DFS+回溯+大小堆判断) A1155 Heap Paths (30 分)

…One thing for sure is that all the keys along any path from the root to a leaf in a max/min heap must be in non-increasing/non-decreasing order.Your job is to check every path in a given complete binary tree, in order to tell if it is a heap or not.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives a positive integer N (1<N≤1,000), the number of keys in the tree. Then the next line contains N distinct integer keys (all in the range of int), which gives the level order traversal sequence of a complete binary tree.
  • Output Specification:
    For each given tree, first print all the paths from the root to the leaves. Each path occupies a line, with all the numbers separated by a space, and no extra space at the beginning or the end of the line. The paths must be printed in the following order: for each node in the tree, all the paths in its right subtree must be printed before those in its left subtree.
    Finally print in a line Max Heap if it is a max heap, or Min Heap for a min heap, or Not Heap if it is not a heap at all.
  • Sample Input 1:
    8
    98 72 86 60 65 12 23 50
    
  • Sample Output 1:
    98 86 23
    98 86 12
    98 72 65
    98 72 60 50
    Max Heap
    
  • Sample Input 2:
    8
    8 38 25 58 52 82 70 60
    
  • Sample Output 2:
    8 25 70
    8 25 82
    8 38 52
    8 38 58 60
    Min Heap
    
  • Sample Input 3:
    8
    10 28 15 12 34 9 8 56
    
  • Sample Output 3:
    10 15 8
    10 15 9
    10 28 34
    10 28 12 56
    Not Heap
    

题意:给出一棵完全二叉树的层序遍历序列,先打印从根结点到所有叶结点的路径,打印顺序先左后右,然后判断这棵完全二叉树是大顶堆还是小顶堆或者不是堆。
思路:我的方法首先是深搜打印所有路径(根右左,先序的镜像),用path数组保存一路上的结点,用index以方便插入新的结点值到数组中或者覆盖旧结点的值;当然也可以用vector,用push_back加入结点,用pop_back回溯。然后可以根据层次序列,从1到N/2,对所有有孩子的结点判断它们的孩子是不是满足要求,和A1147 Heaps (30 分)一样的思路。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int N, a[maxn], path[maxn];
void listpath(int root, int index) {if (root > N) return;else path[index] = a[root];    //root在树中, 先序记录根结点if (root * 2 > N) { //没有孩子结点可以访问, 到达了叶子结点for (int i = 0; i <= index; i++) {if (i > 0) printf(" ");printf("%d", path[i]);}printf("\n");return;} listpath(root * 2 + 1, index + 1); //记录右子树listpath(root * 2, index + 1); //记录左子树
}int main() {scanf("%d", &N);for (int i = 1; i <= N; i++) scanf("%d", &a[i]);listpath(1, 0);int flag = a[1] > a[2] ? 1 : 0; //大顶堆1小顶堆0for (int i = 1; i <= N / 2; i++) {int left = i * 2, right = i * 2 + 1;if (flag == 1 && (a[i] < a[left] || (right <= N && a[i] < a[right]))) { flag = -1; break; }if (flag == 0 && (a[i] > a[left] || (right <= N && a[i] > a[right]))) { flag = -1; break; }}printf("%s Heap\n", flag == 1 ? "Max" : flag == 0 ? "Min" : "Not");return 0;
}

(顶点着色+set+hash) A1154 Vertex Coloring (25 分)

A proper vertex coloring is a labeling of the graph’s vertices with colors such that no two vertices sharing the same edge have the same color. A coloring using at most k colors is called a (proper) k-coloring.

Now you are supposed to tell if a given coloring is a proper k-coloring.

  • Input Specification:
    Each input file contains one test case. For each case, the first line gives two positive integers N and M (both no more than 10​4​​), being the total numbers of vertices and edges, respectively. Then M lines follow, each describes an edge by giving the indices (from 0 to N−1) of the two ends of the edge.

After the graph, a positive integer K (≤ 100) is given, which is the number of colorings you are supposed to check. Then K lines follow, each contains N colors which are represented by non-negative integers in the range of int. The i-th color is the color of the i-th vertex.

  • Output Specification:
    For each coloring, print in a line k-coloring if it is a proper k-coloring for some positive k, or No if not.
  • Sample Input:
    10 11
    8 7
    6 8
    4 5
    8 4
    8 1
    1 2
    1 4
    9 8
    9 1
    1 0
    2 4
    4
    0 1 0 1 4 1 0 1 3 0
    0 1 0 1 4 1 0 1 0 0
    8 1 0 1 4 1 0 5 3 0
    1 2 3 4 5 6 7 8 8 9
    
  • Sample Output:
    4-coloring
    No
    6-coloring
    No
    

题意:给出一个无向图的所有边和每个点的颜色序列,问是否满足所有的边的两个点的颜色不相同。
思路:使用邻接表存图(也可以考虑边集数组);把所有点的颜色存储起来,用set统计颜色个数,枚举所有点的另外一个端点(使用边集数组就是枚举所有边),看看是否颜色相同,全不同就输出颜色个数,否则输出No。

#include <bits/stdc++.h>
using namespace std;
const int maxv = 10010;
vector<int> G[maxv];
int main() {int n, m, a, b, k;scanf("%d%d", &n, &m);for (int i = 0; i < m; i++) {scanf("%d%d", &a, &b);G[a].push_back(b);G[b].push_back(a); }scanf("%d", &k);while (k--) {int colors[n], flag = 1;set<int> s;for (int i = 0; i < n; i++) {scanf("%d", &colors[i]); s.insert(colors[i]);}  for (int i = 0; i < n; i++) {for (int j = 0; j < G[i].size(); j++) {int u = G[i][j];if (colors[i] == colors[u]) { //同一条边的两个端点的颜色相同 printf("No\n");flag = 0; break;} }if (flag == 0) break;}if (flag) printf("%d-coloring\n", s.size());}return 0;
}

【PAT甲级】A1101-A1155刷题记录相关推荐

  1. 【PAT甲级】A1001-A1050刷题记录

    文章目录 A1001 A+B Format (20 分) 0.25 ★(一元多项式加法) A1002 A+B for Polynomials (25 分) 0.21 (单源最短路Dijkstra+边权 ...

  2. 【PAT甲级】A1051-A1100刷题记录

    文章目录 (栈) A1051 Pop Sequence (25 分) 0.47 (静态链表) A1052 Linked List Sorting (25 分) 0.21 (静态树+先根遍历DFS) A ...

  3. 2020年9月PAT甲级满分必备刷题技巧

    2020年7月的考试结束了,除了本次的考题更新,短期内不会更新. [7月题目的特点:首次线上考试,没出链表.树相关的模板题,第2到4题背景新颖,大大降低了抄袭历年代码的可能性,可以看作是线上考试的新趋 ...

  4. PAT甲级官网 刷题(1)

    PAT1138 Postorder Traversal   根据前序和中序遍历确定二叉树,模板题,要求输出第一个后序遍历的节点.TIPS:利用map来映射后序遍历在中序遍历中的位置,否则复杂度过高导致 ...

  5. PAT甲级官网 刷题(3)

    PAT1130 Infix Expression   递归,但是官网有个测试点没过,不知道错在哪里,欢迎指出 #include<iostream>#define ac cin.tie(0) ...

  6. PAT甲级刷题记录-(AcWing)-(Day06树 8题)

    PAT甲级刷题记录-(AcWing)-(Day06树 8题) 课程来源AcWing 其中AcWing中的题目为翻译好的中文题目 今日刷题列表 1110 Complete Binary Tree 111 ...

  7. 小峰峰的pat甲级刷题记录1020

    小峰峰的pat甲级刷题记录1020 方法一:通过后序和中序序列构建树,再层序输出 #include<iostream> #include<vector> using names ...

  8. Python刷题记录(81-90)

    Python刷题记录(81-90) 题目来源PTA平台 PAT (Basic Level) Practice (中文) @TOC 1081 检查密码 本题要求你帮助某网站的用户注册模块写一个密码合法性 ...

  9. 算法笔记CodeUp第一至第六章刷题记录

    文章目录 <算法笔记>2.2小节--C/C++快速入门->顺序结构 1.例题1-1-1 按要求输出信息(1) 2.例题1-1-2 按要求输出信息(2) 3.例题1-2-1 求两个整数 ...

最新文章

  1. python中等高线填充颜色_Python matplotlib使用colormap更改contourf plot中指定值的颜色...
  2. hdu1715 大菲波数
  3. 模块化和组件化的定义以及两者的区别
  4. 【Egret】WebSocket 的使用说明
  5. wxWidgets:VScroll示例
  6. HDU-6470 Count (构造矩阵+矩阵快速幂)
  7. 《机器学习》 周志华学习笔记第五章 神经网络(课后习题) python实现
  8. 计算机五个部件中协调,计算机基础知识(一)
  9. 第七章:在Spark集群上使用文件中的数据加载成为graph并进行操作(2)
  10. 使用mysql++写入BLOB数据
  11. 玉伯的一道课后题题解(关于 IEEE 754 双精度浮点型精度损失)
  12. Java多线程导致的的一个事物性问题
  13. 思科三层+TPAC200+TP AP实现每个SSID独立网段
  14. CMake 手册详解(七)
  15. ILI9431的LCD屏使用,STM32F1控制
  16. 设备综合效率OEE:基于数采的OEE优化分析
  17. Kong的Service 配置
  18. 图解Semaphore信号量之AQS共享锁-非公平模式
  19. mfc中文本文件和文件夹的复制移动
  20. 面试官:抽象工厂模式是什么?

热门文章

  1. 【DP专辑】ACM动态规划总结
  2. MFC模态、非模态对话框
  3. Linux内网服务器实现外网登陆
  4. zedboard Linux JTAG驱动解决There is no current hw_target问题
  5. Play Framework 2.5 环境搭建与新建项目(二)
  6. 开源服务器监控工具——zabbix(一)
  7. PHP Web项目部署记录(一)
  8. 计算机成绩0123,12123驾照考试成绩查询入口-12123驾照考试成绩查询分数的教程
  9. 又是一年春风来:Maggot++成功摆脱Fantis版权!并成功获取自更新模式!
  10. excel-xssfx文件下载导出上下标代码