pat甲级题解
127道甲级题 好像数据结构搭边的 有四十道左右吧
1003. Emergency (25)(最短路)
题意:给一个无向图,每个顶点有一个价值,求解从s到t有几条最短路,然后求出这几条最短路中,价值最高的一条。
思路:直接建图,最短路
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn_v = 500 +5; 5 typedef pair<int, int>pii; 6 7 int vis[maxn_v], dis[maxn_v], nodePeople[maxn_v], ansPeople[maxn_v], ansNum[maxn_v]; 8 9 struct edge 10 { 11 int to, co; 12 bool operator < (const edge &other)const//比较函数反着写,因为优先队列默认权值大的 13 { 14 if(co != other.co) return co > other.co; 15 return to < other.to; 16 } 17 }; 18 vector<edge>G[maxn_v]; 19 20 void dijkstra(int s, int vs) 21 { 22 //初始化 23 for(int i = 0; i <= vs; i++) 24 { 25 vis[i] = 0; 26 dis[i] = INF; 27 ansPeople[i] = 0; 28 ansNum[i] = 0; 29 } 30 31 //给起点s更新数据 32 dis[s] = 0; 33 ansPeople[s] = nodePeople[s]; 34 ansNum[s] = 1;//有用的最短路条数 35 36 //入队 37 priority_queue<edge>que;//因为默认的时候是取最大的,所以重载运算符的时候反过来写 38 que.push({s, dis[s]}); 39 40 while(que.size()) 41 { 42 edge cur = que.top();que.pop(); 43 int u = cur.to; 44 45 if(vis[u]) continue; 46 vis[u] = 1; 47 48 for(auto e : G[u]) 49 { 50 int v = e.to, edgeCost = e.co; 51 //计算有几条最短路 52 if(dis[v] > dis[u] + edgeCost)//能更新,说明v的最短路条数和u相同 53 { 54 ansNum[v] = ansNum[u]; 55 } 56 else if(dis[v] == dis[u] + edgeCost)//发现从u走到v的最短路径长度和 起点s从别的路去v的最短路径长度 相同,说明ansNum[v] = ansNum[v] + ansNum[u] 57 { 58 ansNum[v] += ansNum[u]; 59 } 60 61 if(dis[v] > dis[u] + edgeCost 62 || (dis[v] == dis[u] + edgeCost && ansPeople[v] < ansPeople[u] + nodePeople[v])) 63 { 64 dis[v] = dis[u] + edgeCost; 65 ansPeople[v] = ansPeople[u] + nodePeople[v];//v的总人员 = 到u时的总人员 + v的人员 66 que.push({v, dis[v]}); 67 } 68 } 69 } 70 } 71 72 int main() 73 { 74 int vs, es, sg, eg;//vs顶点数 es边数 sg起点 eg终点 75 scanf("%d%d%d%d", &vs, &es, &sg, &eg); 76 for(int i = 0; i < vs; i++) scanf("%d", &nodePeople[i]); 77 //初始化地图 78 for(int i = 0; i < es; i++) 79 { 80 int u, v, co; 81 scanf("%d%d%d", &u, &v, &co); 82 G[u].push_back({v, co});//无向图建图 83 G[v].push_back({u, co}); 84 } 85 86 dijkstra(sg, vs); 87 printf("%d %d\n", ansNum[eg], ansPeople[eg]); 88 return 0; 89 }
1004. Counting Leaves (30)(dfs)
题意:好像是求一下每层结点中,没有孩子的结点数分别是多少。
思路:n才一百,随便搜一下就好了吧。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 100 +5; 5 typedef pair<int, int>pii; 6 7 int maxlv; 8 int level[maxn]; 9 int cnt[maxn]; 10 vector<int>G[maxn]; 11 12 void dfs(int cur, int lv) 13 { 14 level[cur] = lv; 15 maxlv = max(maxlv, lv); 16 if(G[cur].size() == 0) cnt[lv]++;//如果它没有孩子,说明它这一层没有孩子的结点数++ 17 for(auto o : G[cur]) dfs(o, lv + 1); 18 } 19 20 int main() 21 { 22 int n, m; 23 scanf("%d%d", &n, &m); 24 while(m--) 25 { 26 int pa, num; 27 scanf("%d%d", &pa, &num); 28 while(num--) 29 { 30 int ch; 31 scanf("%d", &ch); 32 G[pa].push_back(ch); 33 } 34 } 35 maxlv = 0; 36 dfs(1, 0); 37 for(int i = 0; i <= maxlv; i++) 38 { 39 printf("%d%c", cnt[i], i == maxlv ? '\n' : ' '); 40 } 41 return 0; 42 }
1013. Battle Over Cities (25)(并查集 or dfs)
题意:从一个无向图里头,取出一个顶点,至少要补几条边能够使得它联通。
思路:就相当于求它的连通分量x,需要连x-1条边。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 1000 +5; 5 typedef pair<int, int>pii; 6 7 int attack; 8 int vis[maxn]; 9 vector<int>G[maxn]; 10 11 void dfs(int cur) 12 { 13 vis[cur] = 1; 14 for(auto o : G[cur]) if(vis[o] == 0 && o != attack) dfs(o); 15 } 16 17 int main() 18 { 19 int vs, es, query; 20 scanf("%d%d%d", &vs, &es, &query); 21 22 while(es--) 23 { 24 int u, v; 25 scanf("%d%d", &u, &v); 26 G[u].push_back(v);//无向图建图 27 G[v].push_back(u); 28 } 29 30 while(query--) 31 { 32 int x; 33 scanf("%d", &x); 34 attack = x; 35 //计算联通分量 36 memset(vis, 0, sizeof(vis)); 37 int scc = 0; 38 for(int i = 1; i <= vs; i++) 39 { 40 if(i == attack || vis[i]) continue;//如果已经被攻占,或者已经被dfs过了,跳过 41 dfs(i); 42 scc++; 43 } 44 printf("%d\n", scc - 1); 45 } 46 return 0; 47 }
1020. Tree Traversals (25)(树的遍历序列转换)
题意:树的遍历序列转换。
思路:递归建树。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 500 +5; 5 6 typedef pair<int, int>pii; 7 int post[35], in[35], lch[35], rch[35]; 8 int build(int L1, int R1, int L2, int R2)//in中序遍历 [L1,R1], post后序遍历[L2,R2] 9 { 10 if(L1 > R1) return -1; 11 int root = post[R2]; 12 int p = L1; 13 while(in[p] != root) p++;//推算出根节点在中序遍历中的位置。 14 int cnt = p - L1; 15 16 lch[root] = build(L1, p - 1, L2, L2 + cnt - 1);//建立左子树 17 rch[root] = build(p + 1, R1, L2 + cnt, R2 - 1);//建立右子树 18 return root; 19 } 20 21 void level_order(int root)//层序遍历 22 { 23 queue<int>que; 24 que.push(root); 25 while(que.size()) 26 { 27 int cur = que.front();que.pop(); 28 int lson = lch[cur], rson = rch[cur]; 29 if(lson != -1) que.push(lson); 30 if(rson != -1) que.push(rson); 31 printf("%d%c", cur, que.size() ? ' ' : '\n'); 32 } 33 } 34 35 int main() 36 { 37 int n; 38 scanf("%d", &n); 39 for (int i = 0; i < n; i++) scanf("%d", &post[i]); 40 for (int i = 0; i < n; i++) scanf("%d", &in[i]); 41 int root = build(0, n - 1, 0, n - 1); 42 level_order(root); 43 return 0; 44 }
1021. Deepest Root (25)(树的直径)
题意:问你这是不是一棵树,然后求出那些顶点:满足条件,以它为根,这颗树最深。
思路:树的直径,两次dfs能计算出树的直径。其实这道题可以再快一点,把三次dfs缩到两次。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 10000 +5; 5 6 int maxLevel; 7 int vis[maxn]; 8 int level[maxn]; 9 vector<int>G[maxn]; 10 vector<int>temp; 11 12 void dfs_scc(int cur) 13 { 14 vis[cur] = 1; 15 for(auto o : G[cur]) if(vis[o] == 0) dfs_scc(o); 16 } 17 18 void dfs_level(int cur, int pa, int lv) 19 {//深搜层数 20 level[cur] = lv; 21 if(lv > maxLevel) 22 { 23 maxLevel = lv; 24 temp.clear(); 25 temp.push_back(cur); 26 } 27 else if(lv == maxLevel) 28 { 29 temp.push_back(cur); 30 } 31 32 for(auto o : G[cur]) 33 { 34 if(o != pa) 35 { 36 dfs_level(o, cur, lv + 1); 37 } 38 } 39 } 40 41 int main() 42 { 43 int vs; 44 scanf("%d", &vs); 45 for(int i = 1; i < vs; i++) 46 { 47 int u, v; 48 scanf("%d%d", &u, &v); 49 G[u].push_back(v);//无向图建图10 50 G[v].push_back(u); 51 } 52 53 int scc = 0; 54 for(int i = 1; i <= vs; i++) 55 { 56 if(vis[i] == 0) dfs_scc(i), scc++; 57 } 58 59 if(scc != 1) 60 { 61 printf("Error: %d components\n", scc); 62 } 63 else 64 { 65 set<int>ans; 66 //第一次dfs 67 maxLevel = 0; 68 temp.clear(); 69 memset(level, 0, sizeof(level)); 70 dfs_level(1, -1, 0); 71 int root = temp[0]; 72 73 for(auto o : temp) ans.insert(o); 74 75 //第二次dfs 76 maxLevel = 0; 77 temp.clear(); 78 memset(level, 0, sizeof(level)); 79 dfs_level(root, -1, 0); 80 root = temp[0]; 81 82 for(auto o : temp) ans.insert(o); 83 84 for(auto o : ans) 85 { 86 printf("%d\n", o); 87 } 88 } 89 return 0; 90 }
1030. Travel Plan (30)(最短路)
题意:
思路:...最短路呗,两个条件的那种。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn_v = 500 +5; 5 typedef pair<int, int>pii; 6 7 int vis[maxn_v], dis[maxn_v], cost[maxn_v], pre[maxn_v]; 8 9 struct edge 10 { 11 int to, dis, co; 12 bool operator < (const edge &other)const//比较函数反着写,因为优先队列默认权值大的 13 { 14 if(dis != other.dis) return dis > other.dis; 15 if(co != other.co) return co > other.co; 16 return to < other.to; 17 } 18 }; 19 vector<edge>G[maxn_v]; 20 21 void dijkstra(int s, int vs) 22 { 23 //初始化 24 for(int i = 0; i <= vs; i++) 25 { 26 pre[i] = -1; 27 vis[i] = 0; 28 dis[i] = INF; 29 cost[i] = INF; 30 } 31 32 //给起点s更新数据 33 dis[s] = 0; 34 cost[s] = 0; 35 //入队 36 priority_queue<edge>que;//因为默认的时候是取最大的,所以重载运算符的时候反过来写 37 que.push({s, dis[s], cost[s]}); 38 39 while(que.size()) 40 { 41 edge cur = que.top();que.pop(); 42 int u = cur.to; 43 44 if(vis[u]) continue; 45 vis[u] = 1; 46 47 for(auto e : G[u]) 48 { 49 if(dis[e.to] > dis[u] + e.dis || 50 dis[e.to] == dis[u] + e.dis && cost[e.to] > cost[u] + e.co) 51 { 52 pre[e.to] = u; 53 dis[e.to] = dis[u] + e.dis; 54 cost[e.to] = cost[u] + e.co; 55 que.push({e.to, dis[e.to], cost[e.to]}); 56 } 57 } 58 } 59 } 60 61 int main() 62 { 63 int vs, es, sg, eg;//vs顶点数 es边数 sg起点 eg终点 64 scanf("%d%d%d%d", &vs, &es, &sg, &eg); 65 66 for(int i = 0; i < es; i++) 67 { 68 int u, v, dis, co; 69 scanf("%d%d%d%d", &u, &v, &dis, &co); 70 G[u].push_back({v, dis, co});//无向图建图 71 G[v].push_back({u, dis, co}); 72 } 73 74 dijkstra(sg, vs); 75 76 stack<int>sta; 77 int now = eg; 78 while(now != -1) 79 { 80 sta.push(now); 81 now = pre[now]; 82 } 83 while(sta.size()) 84 { 85 printf("%d ", sta.top());sta.pop(); 86 } 87 printf("%d %d\n", dis[eg], cost[eg]); 88 return 0; 89 }
1032. Sharing (25)(模拟)
思路:找到两个链表相同的地方就好了。。然后输出就完事了,pat的链表都是数组+map模拟。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 1e5 +5; 5 typedef pair<int, int>pii; 6 7 struct node 8 { 9 char ch; 10 int nxt; 11 }nodes[maxn]; 12 13 14 int main() 15 { 16 int add1, add2, n; 17 scanf("%d%d%d", &add1, &add2, &n); 18 map<int, int>ma; 19 for(int i = 0; i < n; i++) 20 { 21 char ch; 22 int add, nxt; 23 scanf("%d %c %d", &add, &ch, &nxt); 24 nodes[add] = {ch, nxt}; 25 } 26 27 map<int, int>vis;//遍历第一个链表存储所有出现过的结点编号 28 int now = add1; 29 while(now != -1) 30 { 31 vis[now] ++; 32 now = nodes[now].nxt; 33 } 34 35 now = add2; 36 while(now != -1) 37 { 38 if(vis[now] == 0)//这个结点在第一个链表中未出现 39 { 40 now = nodes[now].nxt; 41 } 42 else break;//和第一个链表中的某个结点重合。跳出即可。 43 } 44 if(now != -1) printf("%05d\n", now); 45 else puts("-1"); 46 return 0; 47 }
1043. Is It a Binary Search Tree (25)(二叉搜索树)
题意:让你判断一下这棵树是否是BST。
思路:递归judge。先根据左子树小于根节点,把左右子树切分出来,然后检测一下右子树是否均大于根。然后如果是BST,那么递归建树就行了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 1000 +5; 5 typedef pair<int, int>pii; 6 7 struct node 8 { 9 int val; 10 node *left, *right; 11 node():left(NULL), right(NULL){} 12 }; 13 int pre[maxn];//二叉搜索树的先序序列 14 15 bool judge(int L, int R, int k) 16 { 17 if(L >= R) return true; 18 int p = L + 1; 19 if(k == 0) 20 { 21 while(p <= R && pre[p] < pre[L]) p++;//左子树小于根节点 22 23 for(int i = p; i <= R; i++) 24 { 25 if(pre[i] < pre[L]) return false; 26 } 27 } 28 else if(k == 1)//BST的镜像 29 { 30 while(p <= R && pre[p] >= pre[L]) p++; 31 for(int i = p; i <= R; i++) 32 { 33 if(pre[i] >= pre[L]) return false; 34 } 35 } 36 37 return judge(L + 1, p - 1, k) && judge(p, R, k); 38 } 39 40 node *build(int L, int R, int k) 41 { 42 if(L > R) return NULL; 43 44 node *root = new node(); 45 root->val = pre[L]; 46 47 int p = L + 1; 48 if(k == 0) 49 { 50 while(p <= R && pre[p] < pre[L]) p++;//左子树小于根节点 51 } 52 else if(k == 1)//BST的镜像 53 { 54 while(p <= R && pre[p] >= pre[L]) p++; 55 } 56 root->left = build(L + 1, p - 1, k); 57 root->right = build(p, R, k); 58 return root; 59 } 60 void post_order(node *x, node *root) 61 { 62 if(x->left != NULL) post_order(x->left, root); 63 if(x->right != NULL) post_order(x->right, root); 64 65 printf("%d", x->val); 66 67 if(x != root) printf(" "); 68 else printf("\n"); 69 } 70 71 void solve(int n) 72 { 73 if (judge(0, n - 1, 0)) 74 { 75 puts("YES"); 76 node *root = build(0, n - 1, 0); 77 post_order(root, root); 78 return ; 79 } 80 if (judge(0, n - 1, 1)) 81 { 82 puts("YES"); 83 node *root = build(0, n - 1, 1); 84 post_order(root, root); 85 return ; 86 } 87 88 puts("NO"); 89 } 90 91 int main() 92 { 93 int n; 94 scanf("%d", &n); 95 for (int i = 0; i < n; i++) 96 { 97 scanf("%d", &pre[i]); 98 } 99 solve(n); 100 101 return 0; 102 }
1051. Pop Sequence (25)(栈)
题意:
思路:...栈的基础题
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 5 int maxStore, len, k; 6 int a[1005]; 7 8 bool solve() 9 { 10 int cnt = 1, B = 1; 11 stack<int>sta; 12 while(sta.size() || B <= len) 13 { 14 if(a[cnt] == B)//如果和123456那个序列匹配,就去配对 15 { 16 B++; 17 cnt++; 18 }//如果不匹配那个序列 19 else if(sta.size() && a[cnt] == sta.top())//在看看栈顶是否匹配 20 { 21 sta.pop(); 22 cnt++; 23 }//如果栈顶不匹配 只能压入栈 24 else if(B <= len)//检测此时压入栈的数字是否合法 25 { 26 sta.push(B); 27 B++; 28 if(sta.size() > maxStore - 1) return false;//如果爆了容量了false 29 } 30 else return false; 31 } 32 return cnt == (len + 1); 33 } 34 int main() 35 { 36 scanf("%d%d%d", &maxStore, &len, &k); 37 while(k--) 38 { 39 for(int i = 1; i <= len; i++) 40 { 41 scanf("%d", &a[i]); 42 } 43 if(solve()) puts("YES"); 44 else puts("NO"); 45 } 46 return 0; 47 }
1053. Path of Equal Weight (30)(dfs+打印路径)
题意:给了一棵每个节点都有相应权值的树,规定根节点是0,从根节点向叶子节点计算,若一直走到某个叶子节点的所有权值和为给定的数s,就要保留这条路径。最后路径们按字典序输出吧好像?
思路:
因为考虑到最后输出好像比较麻烦,然后dfs又是那样的顺序,所以我用set读入了数据以后,每一层都从大到小来建树,保证到时候搜出来的路径,直接可以按顺序打印。
通过一次dfs,求出了所有满足条件的路径的终点(叶子节点),保存在ansLeftNode中,然后一条一条的回溯回去,保存在ans数组里,然后输出。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100 + 5; 4 typedef long long LL; 5 typedef pair<int, int>pii; 6 7 int cnt, targetSum; 8 int val[maxn]; 9 vector<int>tree[maxn]; 10 stack<int>ans[maxn]; 11 set<pii>temp[maxn]; 12 vector<int>ansLeftNode; 13 bool dfs(int cur, int pa, LL sum) 14 { 15 int ret = 0; 16 if(tree[cur].size() == 0 && sum == targetSum)//leaf node 17 { 18 ansLeftNode.push_back(cur); 19 return true; 20 } 21 for(auto o : tree[cur]) 22 { 23 if(o != pa) 24 { 25 int ok = dfs(o, cur, sum + val[o]); 26 ret |= ok; 27 } 28 } 29 return ret; 30 } 31 bool dfs_path(int cur, int pa, int eg, LL sum) 32 { 33 int ret = 0; 34 if(cur == eg && sum + val[cur] == targetSum)//leaf node 35 { 36 ans[cnt].push(val[cur]); 37 return true; 38 } 39 for(auto o : tree[cur]) 40 { 41 if(o != pa) 42 { 43 44 int ok = dfs_path(o, cur, eg, sum + val[cur]); 45 ret |= ok; 46 if(ok) 47 { 48 ans[cnt].push(val[cur]); 49 } 50 } 51 } 52 return ret; 53 } 54 int main() 55 { 56 int n, m; 57 scanf("%d%d%d", &n, &m, &targetSum); 58 for(int i = 0; i < n; i++) 59 { 60 scanf("%d", &val[i]); 61 } 62 for (int i = 0; i < m; i++) 63 { 64 int u, num; 65 scanf("%d%d", &u, &num); 66 while(num--) 67 { 68 int v; 69 scanf("%d", &v); 70 temp[u].insert({val[v], v}); 71 } 72 } 73 for(int i = 0; i < n; i++) 74 { 75 set<pii>::reverse_iterator it = temp[i].rbegin(); 76 for(; it != temp[i].rend(); it++) 77 { 78 tree[i].push_back(it->second); 79 } 80 } 81 cnt = 0; 82 dfs(0, -1, val[0]); 83 for(auto o : ansLeftNode) 84 { 85 dfs_path(0, -1, o, 0); 86 cnt++; 87 } 88 89 for(int i = 0; i < cnt; i++) 90 { 91 printf("%d", ans[i].top());ans[i].pop(); 92 while(ans[i].size()) 93 { 94 printf(" %d", ans[i].top());ans[i].pop(); 95 } 96 puts(""); 97 } 98 return 0; 99 }
1057. Stack (30)(线段树)
题意:有一个东西在不停的模拟栈的进退,然后在制定的操作时,要查询栈中的median value。
思路:是一个线段树的单点更新,单点查询的题。线段树查询第k大的数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5 + 5; 4 const int INF = 0x3f3f3f3f; 5 typedef long long LL; 6 #define lson l, m, rt << 1 7 #define rson m + 1, r, rt << 1 | 1 8 9 int sum[maxn << 2];//开四倍大小空间。线段树 10 11 void pushup(int rt){sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];}; 12 13 void build(int l, int r, int rt) 14 { 15 if(l == r) 16 { 17 sum[rt] = 0; 18 return ; 19 } 20 int m = (l + r) >> 1; 21 build(lson); 22 build(rson); 23 pushup(rt); 24 } 25 26 void modify(int l, int r, int rt, int p, int add)//在[l,r]区间内,当前结点编号为rt,查找一个结点编号为p的结点,更新add 27 { 28 if(l == r) 29 { 30 sum[rt] += add;//对当前结点进行更新 31 return ; 32 } 33 int m = (l + r) >> 1; 34 if(p <= m) modify(lson, p, add); 35 else modify(rson, p, add); 36 pushup(rt);//更新完所需叶子结点以后,需要pushup向上传递更新后的信息 37 } 38 39 int query(int l, int r, int rt, int k) 40 { 41 if(l == r) return l;// 查询第k大的数 42 int m = (l + r) >> 1; 43 if(sum[rt << 1] >= k) return query(lson, k);//如果左子树的数的数量大于等于k,显然可以左子树里 44 else return query(rson, k - sum[rt << 1]); 45 } 46 47 48 49 int main() 50 { 51 int n; 52 scanf("%d", &n); 53 stack<int>sta; 54 55 while(n--) 56 { 57 char s[20]; 58 scanf("%s", s); 59 if(s[1] == 'o')//pop 60 { 61 if(sta.size()) 62 { 63 int temp = sta.top(); 64 printf("%d\n", temp); 65 sta.pop(); 66 modify(1, maxn, 1, temp, -1);//从线段树中清除 67 } 68 else puts("Invalid"); 69 } 70 else if(s[1] == 'u')//push 71 { 72 int x; 73 scanf("%d", &x); 74 sta.push(x); 75 modify(1, maxn, 1, x, 1);//线段树更新 76 } 77 else if(s[1] == 'e')//PeekMedian 78 { 79 //线段树里查 80 if(sta.size()) 81 { 82 int x = (sta.size() + 1) / 2; 83 printf("%d\n", query(1, maxn, 1, x)); 84 } 85 else puts("Invalid"); 86 } 87 } 88 return 0; 89 }
1064. Complete Binary Search Tree (30)(完全二叉搜索树)
题意:把一个序列填充成一个完全二叉搜索树。输出层序遍历的结果
思路:query函数是计算左右子树的结点个数。因为完全二叉树的性质,可以算出来。
写完以后,发现。傻逼了啊!!!你们记不记得有个东西叫做堆,手写堆都会的对吧。它就是完全BST,有一个特性啊!!!它的左右儿子结点编号为2*i,2*i+1。所以这题其实。。可以很简单对吧。
1 /* 2 把一个序列填充成一个完全二叉搜索树。输出层序遍历的结果 3 */ 4 #include <bits/stdc++.h> 5 using namespace std; 6 const int maxn = 1e3 + 5; 7 8 int a[maxn], lch[2000 + 5], rch[2000 +5];//注意 lch和rch数组的大小 和 给出的数字的范围息息相关。写指针就无关了 9 10 void query(int n, int &lsonSize, int &rsonSize) 11 {//n是整棵树的总结点数 12 if(n == 1) 13 { 14 lsonSize = rsonSize = 0; 15 return ; 16 } 17 //求出整棵树的最深层数 18 //显然此时层数必定大于等于2 19 int level = 2; 20 while(n >= ((1 << level) - 1)) 21 { 22 level++; 23 } 24 lsonSize = rsonSize = (1 << (level - 2)) - 1; 25 lsonSize += min(n - ((1 << (level - 1)) - 1), 1 << (level - 2));// 左子树的最后一层最多只有(2^(level - 1) / 2) 个,这里是用总的结点数,减掉前level-1层的满二叉搜索树的结点个数 26 rsonSize += n - 1 - lsonSize; 27 } 28 29 int build(int L, int R) 30 { 31 if(L > R) return -1; 32 int totNodes = R - L + 1; 33 int lsonSize = 0, rsonSize = 0; 34 query(totNodes, lsonSize, rsonSize); 35 int root = a[L + lsonSize]; 36 37 lch[root] = build(L, L + lsonSize - 1); 38 rch[root] = build(L + lsonSize + 1, R); 39 return root; 40 } 41 42 void level_order(int root) 43 { 44 queue<int>que; 45 que.push(root); 46 while(que.size()) 47 { 48 int cur = que.front();que.pop(); 49 if(lch[cur] != -1) que.push(lch[cur]); 50 if(rch[cur] != -1) que.push(rch[cur]); 51 if(cur != root) printf(" "); 52 printf("%d", cur); 53 } 54 puts(""); 55 } 56 57 int main() 58 { 59 int n; 60 scanf("%d", &n); 61 for (int i = 0; i < n; i++) 62 { 63 scanf("%d", &a[i]); 64 } 65 sort(a, a + n); 66 int root = build(0, n - 1); 67 level_order(root); 68 return 0; 69 }
1066. Root of AVL Tree (25)(avl树的旋转)
题意:问你最后avl树的根是谁。
思路:avl树的旋转的模拟。课本基础知识。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 30 + 5; 4 5 int a[maxn]; 6 7 struct node 8 { 9 int val, height; 10 node *left, *right; 11 node(int x):left(NULL), right(NULL), val(x), height(0){} 12 }; 13 14 int Height(node *p) 15 { 16 if (p == NULL) return -1; 17 else return p->height; 18 } 19 20 node *avl_RightRotate(node *k2);//LL旋转 21 node *avl_LeftRightRotate(node *k3);//LR旋转 22 node *avl_LeftRotate(node *k2);//RR旋转 23 node *avl_RightLeftRotate(node *k3);//RL旋转 24 25 26 node *avl_RightRotate(node *k2)//LL旋转 27 { 28 node *k1; 29 k1 = k2->left; 30 k2->left = k1->right; 31 k1->right = k2; 32 33 k2->height = max(Height(k2->left), Height(k2->right)) + 1; 34 k1->height = max(Height(k1->left), Height(k1->right)) + 1; 35 return k1;//新的根结点 36 } 37 38 node *avl_LeftRightRotate(node *k3)//LR旋转 39 { 40 k3->left = avl_LeftRotate(k3->left); 41 return avl_RightRotate(k3); 42 } 43 44 node *avl_LeftRotate(node *k2)//RR旋转 45 { 46 node *k1; 47 k1 = k2->right; 48 k2->right = k1->left; 49 k1->left = k2; 50 51 k2->height = max(Height(k2->left), Height(k2->right)) + 1; 52 k1->height = max(Height(k1->left), Height(k1->right)) + 1; 53 return k1;//新的根结点 54 } 55 56 node *avl_RightLeftRotate(node *k3)//RL旋转 57 { 58 k3->right = avl_RightRotate(k3->right); 59 return avl_LeftRotate(k3); 60 } 61 62 63 node *avl_insert(int x, node *T) 64 { 65 if (T == NULL) 66 { 67 T = new node(x); 68 } 69 else if (x < T->val)//要插入的元素x比当前结点的值小 70 {//插入T的左子树中 71 T->left = avl_insert(x, T->left); 72 if(Height(T->left) - Height(T->right) == 2) 73 { 74 if (x < T->left->val)//插入到T的左子树的左边,是LL旋转 75 T = avl_RightRotate(T);//left单旋 76 else if (x > T->left->val)//插入到左子树的右边,是LR旋转 77 T = avl_LeftRightRotate(T);//left双旋 78 } 79 } 80 else if (x > T->val)//要插入的元素x比当前结点的值大 81 {//插入T的右子树中 82 T->right = avl_insert(x, T->right); 83 if (Height(T->right) - Height(T->left) == 2) 84 { 85 if (x > T->right->val)//插入到右子树的右边是,RR旋转 86 T = avl_LeftRotate(T);//right单选 87 else if (x < T->right->val)//插入到右子树的左边是,RL旋转 88 T = avl_RightLeftRotate(T);//right双旋 89 } 90 } 91 92 T->height = max(Height(T->left), Height(T->right)) + 1; 93 return T; 94 } 95 96 int main() 97 { 98 int n; 99 scanf("%d", &n); 100 node *root = NULL; 101 102 for (int i = 0; i < n; i++) 103 { 104 int x; 105 scanf("%d", &x); 106 root = avl_insert(x, root); 107 } 108 printf("%d\n", root->val); 109 110 return 0; 111 }
1074. Reversing Linked List (25)(模拟)
题意:链表每k个,一翻转。
思路:这题很恶心啊,题意没说清楚,它给的数据可能是好几条链,沃日。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5 + 5; 4 typedef pair<int, int>pii; 5 6 struct node 7 { 8 int val, nxt; 9 }nodes[maxn]; 10 int temp[maxn]; 11 12 int main() 13 { 14 int head, n, reverseLen; 15 scanf("%d%d%d", &head, &n, &reverseLen); 16 for(int i = 0; i < n; i++) 17 { 18 int address, val, nxt; 19 scanf("%d%d%d", &address, &val, &nxt); 20 nodes[address] = {val, nxt}; 21 } 22 23 int now = head; 24 int cnt = 0; 25 while(now != -1) 26 { 27 temp[cnt++] = now; 28 now = nodes[now].nxt; 29 } 30 31 //找出每一个翻转区间的起始位置 32 for(int i = 0; i + reverseLen <= cnt; i += reverseLen) 33 { 34 reverse(temp + i, temp + i + reverseLen); 35 } 36 37 38 for(int i = 0; i < cnt; i++) 39 { 40 printf("%05d %d ", temp[i], nodes[temp[i]].val); 41 if(i == cnt - 1) printf("-1\n"); 42 else printf("%05d\n", temp[i + 1]); 43 } 44 return 0; 45 }
1076. Forwards on Weibo (30)(bfs)
思路:看清楚谁follow谁就行了,bfs。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1000 + 5; 4 typedef pair<int, int>pii; 5 6 int level[maxn]; 7 vector<int>follower[maxn]; 8 9 int bfs(int s, int L) 10 { 11 memset(level, -1, sizeof(level)); 12 13 level[s] = 0; 14 15 queue<pii>que; 16 que.push({s, level[s]}); 17 18 int ret = 0; 19 while(que.size()) 20 { 21 pii cur = que.front();que.pop(); 22 if(cur.second > L) continue;//只能传L层 23 24 ret++; 25 for(auto o : follower[cur.first]) 26 { 27 if(level[o] == -1) 28 { 29 level[o] = level[cur.first] + 1; 30 que.push({o, level[o]}); 31 } 32 } 33 } 34 return ret - 1;//去除自身 35 } 36 37 int main() 38 { 39 int n, L; 40 scanf("%d%d", &n, &L); 41 for(int i = 1; i <= n; i++) 42 { 43 int k; 44 scanf("%d", &k); 45 while(k--) 46 { 47 int x; 48 scanf("%d", &x); 49 follower[x].push_back(i);//谁跟随谁看清楚 50 } 51 } 52 int query; 53 scanf("%d", &query); 54 while(query--) 55 { 56 int x; 57 scanf("%d", &x); 58 cout << bfs(x, L) << endl; 59 } 60 return 0; 61 }
1078. Hashing (25)(哈希表的二次探测)
思路:
不是筛出10000以内的素数,要多筛一点,确保筛到了比10000大的最小的素数,同时,要小心那几个数组开的大小。其实也可以用最普通的isPrime去判。pat数据水的...
还考了一个.....哈希的二次探测。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 2e4 + 5; 4 5 int tot; 6 int vis[maxn], check[maxn], prime[maxn]; 7 8 void sieve(int n) 9 { 10 tot = 0; 11 check[0] = check[1] = 1;//check为0时是素数 12 for (int i = 2; i <= n; i++) 13 { 14 if (!check[i]) 15 { 16 prime[tot++] = i; 17 for (int j = i * i; j <= n; j += i) 18 { 19 check[j] = 1; 20 } 21 } 22 } 23 24 } 25 void modify(int &x) 26 { 27 x = *lower_bound(prime, prime + tot, x); 28 } 29 30 int main() 31 { 32 sieve(12000); 33 int Msize, n; 34 scanf("%d%d", &Msize, &n); 35 36 modify(Msize); 37 38 for (int i = 0; i < n; i++) 39 { 40 int x; 41 scanf("%d", &x); 42 int pos = x % Msize; 43 if(vis[pos] == 0) 44 { 45 vis[pos] = 1; 46 printf("%d", pos); 47 48 } 49 else 50 { 51 int ok = 0; 52 for (int j = 0; j < Msize; j++)//哈希表的二次探测 53 { 54 int nxtPos = (j * j + pos) % Msize; 55 if(vis[nxtPos] == 0) 56 { 57 vis[nxtPos] = 1; 58 printf("%d", nxtPos); 59 ok = 1; 60 break; 61 } 62 } 63 if(ok == 0) printf("-"); 64 } 65 printf(i == n - 1 ? "\n" : " "); 66 } 67 68 69 return 0; 70 }
1079. Total Sales of Supply Chain (25)
思路:
很简单的深搜。但是注意一点。处理零售商的加和的时候 一定要放在for(auto)遍历子节点之前,至于为什么? 想想看
1 1.8 1
0 5
这组样例
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5 + 5; 4 5 double ans; 6 vector<int>tree[maxn]; 7 int amount[maxn]; 8 9 void dfs(int cur, double curPrice, double rate) 10 { 11 double netPrice = curPrice * (1.0 + rate / 100); 12 13 if(amount[cur])//是零售商 14 { 15 ans += amount[cur] * curPrice; 16 return; 17 } 18 19 for(auto o : tree[cur]) 20 { 21 dfs(o, netPrice, rate); 22 } 23 } 24 25 int main() 26 { 27 int n; 28 double rootPrice, rate; 29 scanf("%d%lf%lf", &n, &rootPrice, &rate); 30 for(int i = 0; i < n; i++) 31 { 32 int k; 33 scanf("%d", &k); 34 if(k == 0) 35 { 36 scanf("%d", &amount[i]);//是零售商 37 continue; 38 } 39 //供应商 40 while(k--) 41 { 42 int x; 43 scanf("%d", &x); 44 tree[i].push_back(x); 45 } 46 } 47 ans = 0.0; 48 dfs(0, rootPrice, rate); 49 printf("%.1f\n", ans); 50 return 0; 51 }
1086. Tree Traversals Again (25)(树的遍历序列转换)
思路:思考一下,可以发现入栈的顺序,是根左右,是前序序列。出栈的顺序是,左根右,是中序序列。那么就很简单了啊,求一个后序序列会的吧。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100 + 5; 4 5 vector<int>pre, in; 6 int lch[35], rch[35]; 7 8 int build(int L1, int R1, int L2, int R2)// pre in 9 { 10 if(L1 > R1) return -1; 11 cout << "L1 = " << L1 << " R1 = " << R1 <<endl; 12 int root = pre[L1]; 13 int p = L2; 14 while(in[p] != root) p++; 15 int cnt = p - L2; 16 lch[root] = build(L1 + 1, L1 + cnt, L2, p - 1); 17 rch[root] = build(L1 + cnt + 1, R1, p + 1, R2); 18 if(L1 == R1)cout << "p = " << p << " lch[root] = " <<lch[root] << " rch[root] = " << rch[root] <<endl; 19 return root; 20 } 21 void post_order(int x, int root) 22 { 23 if(lch[x] != -1) post_order(lch[x], root); 24 if(rch[x] != -1) post_order(rch[x], root); 25 printf("%d%c", x, x == root ? '\n' : ' '); 26 } 27 int main() 28 { 29 int n; 30 scanf("%d", &n); 31 stack<int>sta; 32 int cnt = 0; 33 for (int i = 0; i < 2 * n; i++) 34 { 35 char s[10]; 36 scanf("%s", s); 37 38 if (s[1] == 'u')//push 39 { 40 int x; 41 scanf("%d", &x); 42 sta.push(x); 43 pre.push_back(x); 44 } 45 else 46 { 47 in.push_back(sta.top()); 48 sta.pop(); 49 } 50 } 51 int root = build(0, n - 1, 0, n - 1); 52 post_order(root, root); 53 return 0; 54 }
1091. Acute Stroke (30)(bfs)
思路:bfs,三维的宽搜,不能用深搜,会爆栈的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 30 + 5; 4 5 int m, n, L, T; 6 int ma[65][1300][130]; 7 #define isInside(x, y, z) (0 <= x && x < L && 0 <= y && y < m && 0 <= z && z < n) 8 9 int dx[] = {-1, 0, 0, 0, 0, 1}; 10 int dy[] = {0, -1, 0, 0, 1, 0}; 11 int dz[] = {0, 0, -1, 1, 0, 0}; 12 struct node 13 { 14 int x, y, z; 15 }; 16 int bfs(int x, int y, int z) 17 { 18 int ret = 1; 19 queue<node>que; 20 que.push({x, y, z}); 21 ma[x][y][z] = 0; 22 while(que.size()) 23 { 24 node cur = que.front();que.pop(); 25 26 for(int kind = 0; kind < 6; kind++) 27 { 28 int fx = cur.x + dx[kind], fy = cur.y + dy[kind], fz = cur.z + dz[kind]; 29 if(isInside(fx, fy, fz) && ma[fx][fy][fz] == 1) 30 { 31 ma[fx][fy][fz] = 0; 32 ret++; 33 que.push({fx, fy, fz}); 34 } 35 } 36 37 } 38 return ret; 39 } 40 41 int main() 42 { 43 scanf("%d%d%d%d", &m, &n, &L, &T); 44 for(int i = 0; i < L; i++) 45 { 46 for(int j = 0; j < m; j++) 47 { 48 for(int k = 0; k < n; k++) 49 { 50 scanf("%d", &ma[i][j][k]); 51 } 52 } 53 } 54 int ans = 0; 55 for(int i = 0; i < L; i++) 56 { 57 for(int j = 0; j < m; j++) 58 { 59 for(int k = 0; k < n; k++) 60 { 61 if(ma[i][j][k] == 1) 62 { 63 int temp = bfs(i, j, k); 64 if(temp >= T) ans += temp; 65 } 66 } 67 } 68 } 69 cout << ans << endl; 70 return 0; 71 }
1097. Deduplication on a Linked List (25)
思路:map+数组一通模拟就好了。先分类,哪些是第一次出现绝对值的,留下来left,不然要删掉delete,然后把两个容器里的东西重新串起来即可。
1 #include <stdio.h> 2 #include <bits/stdc++.h> 3 using namespace std; 4 const int mod = 1e9 + 7; 5 const int maxn = 1e5 + 5; 6 const int INF = 0x3f3f3f3f; 7 typedef long long LL; 8 typedef pair<int, int>pii; 9 typedef pair<LL, LL>pLL; 10 typedef unsigned long long ull; 11 12 13 struct node 14 { 15 int key, nex; 16 }nodes[maxn]; 17 18 int main() 19 { 20 int head, n; 21 scanf("%d%d", &head, &n); 22 23 vector<int>del; 24 vector<int>left; 25 map<int, int>ma; 26 27 for(int i = 0; i < n; i++) 28 { 29 int add, key, nex; 30 scanf("%d%d%d", &add, &key, &nex); 31 nodes[add] = {key, nex}; 32 } 33 34 //判断其键值的绝对值是否出现过 35 int now = head; 36 while(now != -1) 37 { 38 int key = abs(nodes[now].key); 39 if(ma[key] == 0) ma[key]++, left.push_back(now);//尚未出现过 说明这个结点可以留下来,更新map 40 else del.push_back(now);//已经出现过 说明要delete掉 41 now = nodes[now].nex; 42 } 43 44 45 for(int i = 0; i < left.size(); i++) 46 { 47 int cur = left[i]; 48 nodes[cur].nex = -1;//当前结点cur 的 nex指针指空 49 if(i == 0) continue;//i==0时没有前继结点 50 51 int last = left[i - 1];//把前一个结点left的nex指针 指到 当前结点cur身上 52 nodes[last].nex = cur; 53 } 54 55 for(int i = 0; i < del.size(); i++) 56 { 57 int cur = del[i]; 58 nodes[cur].nex = -1;//当前结点cur 的 nex指针指空 59 if(i == 0) continue;//i==0时没有前继结点 60 61 int last = del[i - 1];//把前一个结点left的nex指针 指到 当前结点cur身上 62 nodes[last].nex = cur; 63 } 64 //输出结果 65 for(auto o : left) 66 { 67 printf("%05d %d ", o, nodes[o].key);//因为所有编号是五位整数,用int存,%05d输出比较方便。 68 if(nodes[o].nex == -1) puts("-1");//但是%05d输出的时候,遇到-1,会变成-00001,所以要特判 69 else printf("%05d\n", nodes[o].nex); 70 } 71 72 for(auto o : del) 73 { 74 printf("%05d %d ", o, nodes[o].key); 75 if(nodes[o].nex == -1) puts("-1"); 76 else printf("%05d\n", nodes[o].nex); 77 } 78 return 0; 79 }
1099. Build A Binary Search Tree (30)(给定结构的BST的填充)
题意:建立一棵给定结构的二叉搜索树,并且进行层序遍历。
思路:利用BST的性质,左小右大,那么它的中序遍历就是一个从小到大的有序数组对吧。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e3 + 5; 4 5 int cnt; 6 int lch[maxn], rch[maxn], a[maxn], val[maxn]; 7 8 void dfs(int x) 9 { 10 int lson = lch[x], rson = rch[x]; 11 12 if(lson != -1)//左子树不为空,就进去 13 { 14 dfs(lson); 15 } 16 val[x] = a[cnt]; 17 cnt++; 18 if(rson != -1) dfs(rson); 19 } 20 21 void level_order(int root) 22 { 23 queue<int>que; 24 que.push(root); 25 while(que.size()) 26 { 27 int cur = que.front();que.pop(); 28 int lson = lch[cur], rson = rch[cur]; 29 if(lson != -1) que.push(lson); 30 if(rson != -1) que.push(rson); 31 32 if(cur != root) printf(" "); 33 printf("%d", val[cur]); 34 } 35 } 36 37 int main() 38 { 39 int n; 40 scanf("%d", &n); 41 for (int i = 0; i < n; i++) 42 { 43 int l, r; 44 scanf("%d%d", &l, &r); 45 lch[i] = l; 46 rch[i] = r; 47 } 48 for(int i = 0; i < n; i++) 49 { 50 scanf("%d", &a[i]); 51 } 52 sort(a, a + n); 53 cnt = 0; 54 dfs(0); 55 level_order(0); 56 57 return 0; 58 }
1102. Invert a Binary Tree (25)
题意:给你一个树的输入,让你把数左右互换(invert)然后对其进行层序遍历和中序遍历。
思路:...输出的时候左右儿子调换一下就行了呗。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100 + 5; 4 5 int cnt, n; 6 int lch[15], rch[15], vis[15]; 7 8 void in_order(int x) 9 { 10 if(rch[x] != -1) in_order(rch[x]); 11 printf("%d%c", x, cnt++ == n ? '\n' : ' '); 12 if(lch[x] != -1) in_order(lch[x]); 13 } 14 15 void level_order(int root)//层序遍历 16 { 17 queue<int>que; 18 que.push(root); 19 while(que.size()) 20 { 21 int cur = que.front();que.pop(); 22 int lson = lch[cur], rson = rch[cur]; 23 24 if(rson != -1) que.push(rson); 25 if(lson != -1) que.push(lson); 26 27 printf("%d%c", cur, que.size() ? ' ' : '\n'); 28 } 29 } 30 31 int main() 32 { 33 scanf("%d", &n); 34 for(int i = 0; i < n; i++) 35 { 36 getchar(); 37 char left, right; 38 scanf("%c %c", &left, &right); 39 if(left != '-') 40 { 41 int lson = left - '0'; 42 vis[lson] = 1; 43 lch[i] = lson; 44 } 45 else lch[i] = -1; 46 47 if(right != '-') 48 { 49 int rson = right - '0'; 50 vis[rson] = 1; 51 rch[i] = rson; 52 } 53 else rch[i] = -1; 54 } 55 //如果不在各个结点的子树中出现,则这个编号为根节点 56 int root; 57 for(int i = 0; i < n; i++) 58 { 59 if(vis[i] == 0) root = i; 60 } 61 62 //翻转树以后的序列,所以在这两个函数中左右倒转 63 level_order(root); 64 cnt = 1; 65 in_order(root); 66 return 0; 67 }
1110. Complete Binary Tree (25)(判断是否为完全二叉树)
题意:这是否是一个完全二叉树。
思路:基础题吧。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100 + 5; 4 5 int cnt, n; 6 int lch[25], rch[25], vis[25]; 7 8 void in_order(int x) 9 { 10 if(rch[x] != -1) in_order(rch[x]); 11 printf("%d%c", x, cnt++ == n ? '\n' : ' '); 12 if(lch[x] != -1) in_order(lch[x]); 13 } 14 int isCompleteBinaryTree; 15 16 int level_order(int root)//层序遍历 17 {//整棵树压进队列中,由完全二叉树的性质可知,第一个层序遍历的空结点就是整棵树的终点,检查此时是否n个结点都已经被遍历完全 18 // int flag = 0; 19 queue<int>que; 20 que.push(root); 21 while(que.size()) 22 { 23 int cur = que.front();que.pop(); 24 if(cur == -1) 25 { 26 if(cnt != n) isCompleteBinaryTree = 0; 27 continue; 28 } 29 cnt++; 30 int lson = lch[cur], rson = rch[cur]; 31 que.push(lson); 32 que.push(rson); 33 if(cnt == n) return cur; 34 } 35 } 36 37 int main() 38 { 39 scanf("%d", &n); 40 getchar(); 41 for(int i = 0; i < n; i++) 42 { 43 char left[10], right[10]; 44 scanf("%s %s", left, right); 45 46 int lson, rson; 47 if(left[0] != '-') 48 { 49 lson = 0; 50 for(int i = 0; i < strlen(left); i++) 51 { 52 lson = lson * 10 + left[i] - '0'; 53 } 54 vis[lson] = 1; 55 lch[i] = lson; 56 } 57 else lch[i] = -1; 58 59 if(right[0] != '-') 60 { 61 rson = 0; 62 for(int i = 0; i < strlen(right); i++) 63 { 64 rson = rson * 10 + right[i] - '0'; 65 } 66 67 vis[rson] = 1; 68 rch[i] = rson; 69 } 70 else rch[i] = -1; 71 72 } 73 //如果不在各个结点的子树中出现,则这个编号为根节点 74 int root; 75 for(int i = 0; i < n; i++) 76 { 77 if(vis[i] == 0) root = i; 78 } 79 isCompleteBinaryTree = 1; 80 int ret = level_order(root); 81 if(isCompleteBinaryTree) 82 { 83 printf("YES %d\n", ret); 84 } 85 else 86 { 87 printf("NO %d\n", root); 88 } 89 90 return 0; 91 }
1114. Family Property (25)(并查集)
题意:给出每个人的家庭成员信息和自己的房产个数与房产总面积,让你统计出每个家庭的人口数、人均房产个数和人均房产面积。第一行输出家庭个数,随后每行输出家庭成员的最小编号、家庭人口数、人均房产个数、人均房产面积。
思路:...并查集模拟题。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn = 1e4 + 5; 5 6 int pa[maxn], vis[maxn]; 7 int sum[maxn], peo[maxn], num[maxn], small[maxn];//房产总面积,人数,房产套数,最小编号 8 9 void init(int n) 10 { 11 for (int i = 0; i <= n; i++) 12 { 13 pa[i] = small[i] = i; 14 peo[i] = 1; 15 } 16 } 17 int uf_find(int x){return pa[x] == x ? x : uf_find(pa[x]);} 18 19 void join(int x, int y) 20 { 21 int fx = uf_find(x), fy = uf_find(y); 22 if (fx != fy)//把fy 并到fx上 23 pa[fy] = fx; 24 } 25 struct family 26 {//按人均面积降序输出,若有并列,则按成员编号的升序输出。 27 int id, small, peo, num, sum; 28 bool operator < (const family& other) 29 { 30 if (sum * other.peo != other.sum * peo)//防止浮点误差 人均面积 sum / peo other.sum / other.peo 31 return sum * other.peo > other.sum * peo; 32 return small < other.small;//试了一下 题意指的好像是最小成员编号的升序 33 } 34 }; 35 36 int main() 37 { 38 init(10000);//四位编号因此,最多10000个 39 int n; 40 scanf("%d", &n); 41 for (int i = 0; i < n; i++) 42 { 43 int cur, fa, mo, k; 44 scanf("%d%d%d%d", &cur, &fa, &mo, &k);//输入自身编号 父母编号,孩子数量 45 vis[cur] = 1;//标记i结点,可能作为某个并查集的根节点 46 int a[10]; 47 for (int j = 0; j < k; j++) scanf("%d", &a[j]);//输入他的孩子们 48 scanf("%d%d", &num[cur], &sum[cur]);//输入他拥有的房产套数,住房面积 49 50 //更新完当前用户的房产情况后。join父母,孩子 51 //合并并查集的过程中pa[fy] = fx,也就是把后者合并到前者上, 52 //让每一个并查集的根节点出现在vis[i] = 1的i结点上 53 if (fa != -1) join(cur, fa); 54 if (mo != -1) join(cur, mo); 55 for (int j = 0; j < k; j++) 56 if (a[j] != -1) 57 join(cur, a[j]); 58 59 } 60 for (int i = 0; i <= 10000; i++) 61 { 62 int fi = uf_find(i); 63 if (i != fi) 64 {//如果这个编号的根结点,不是自己,把它的最小编号,人口数量,房产套数,住房面积更新到根结点去 65 sum[fi] += sum[i]; 66 peo[fi] += peo[i]; 67 num[fi] += num[i]; 68 small[fi] = min(small[fi], small[i]); 69 } 70 } 71 72 vector<family>vec;//记录所有family的根节点 73 74 for (int i = 0; i <= 10000; i++) 75 { 76 if (vis[i] && uf_find(i) == i)//如果这个结点vis[i]==1并且它的根节点是他自身,那么压进vec 77 vec.push_back({i, small[i], peo[i], num[i], sum[i]}); 78 } 79 sort(vec.begin(), vec.end());//按需求排序 80 81 printf("%d\n", vec.size());//输出并查集的数量 82 for (auto o : vec) 83 {//输出每个并查集的最小编号 家庭人口数 人均房产套数 人均房产面积 84 printf("%04d %d %.3f %.3f\n", o.small, o.peo, 1.0 * o.num / o.peo, 1.0 * o.sum / o.peo); 85 } 86 return 0; 87 }
1115. Counting Nodes in a BST (30)(BST插入操作+dfs)
题意:给你一棵BST的插入序列,问你插完后,这颗BST的最下面两层,各有几个顶点。
思路:完成BST的插入操作,然后搜一遍就完了呗。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100 + 5; 4 5 struct node 6 { 7 int val; 8 node *left, *right; 9 node():left(NULL), right(NULL){} 10 }; 11 12 node *BST_insert(node *T, int val) 13 { 14 if(T == NULL) 15 { 16 T = new node(); 17 T->val = val; 18 } 19 else if(val <= T->val)//题目此时对左子树的定义是<= 20 { 21 T->left = BST_insert(T->left, val); 22 } 23 else 24 { 25 T->right = BST_insert(T->right, val); 26 } 27 return T; 28 } 29 30 31 int level[1005]; 32 int maxLevel = -1; 33 void dfs_level(node *root, int lv) 34 { 35 if(root == NULL) return; 36 maxLevel = max(maxLevel, lv); 37 level[lv]++; 38 dfs_level(root->left, lv + 1); 39 dfs_level(root->right, lv + 1); 40 } 41 42 int main() 43 { 44 int n; 45 scanf("%d", &n); 46 node *root = NULL; 47 for (int i = 0; i < n; i++) 48 { 49 int x; 50 scanf("%d", &x); 51 root = BST_insert(root, x); 52 } 53 54 dfs_level(root,1); 55 int n2 = level[maxLevel], n1 = level[maxLevel - 1]; 56 //不知道为什么下面这个...最后一个测试点过不去 57 // int n2 = level[1], n1 = level[2]; 58 // for(int i = 3; i <= maxLevel; i++) 59 // { 60 // n2 = n1; 61 // n1 = level[i]; 62 // } 63 printf("%d + %d = %d\n", n1, n2, n1 + n2); 64 65 return 0; 66 }
1118. Birds in Forest (25)
题意:有一些鸟在一棵树上,然后问你有几棵树,几只鸟,那几只鸟在一棵树上。
思路:基础并查集。。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e4 + 5; 4 5 int vis[maxn], pa[maxn]; 6 void init(int n){for(int i = 1; i <= n; i++) vis[i] = 0, pa[i] = i;} 7 int uf_find(int x){return x == pa[x] ? x : uf_find(pa[x]);} 8 bool same(int x, int y){return uf_find(x) == uf_find(y);} 9 void uf_join(int x, int y) 10 { 11 int fx = uf_find(x), fy = uf_find(y); 12 if(fx != fy) 13 pa[fx] = fy; 14 } 15 16 int main() 17 { 18 init(maxn); 19 int n; 20 scanf("%d", &n); 21 for(int i = 0; i < n; i++) 22 { 23 int k, x, y; 24 scanf("%d", &k); 25 26 if(k >= 2) 27 { 28 scanf("%d", &x); 29 vis[x] = 1; 30 for(int j = 0; j < k - 1; j++) 31 { 32 scanf("%d", &y); 33 vis[y] = 1; 34 uf_join(x, y); 35 } 36 } 37 else if(k == 1) 38 { 39 scanf("%d", &x); 40 vis[x] = 1; 41 } 42 } 43 int cntTree = 0, cntBird = 0; 44 for(int i = 1; i <= 10000; i++) 45 { 46 if(vis[i]) 47 { 48 cntBird++; 49 cntTree += (i == pa[i]); 50 } 51 } 52 53 printf("%d %d\n", cntTree, cntBird); 54 int query; 55 scanf("%d", &query); 56 while(query --) 57 { 58 int x, y; 59 scanf("%d%d", &x, &y); 60 if(same(x, y)) puts("Yes"); 61 else puts("No"); 62 } 63 64 return 0; 65 }
1119. Pre- and Post-order Traversals (30)
题意:给出前序,后序序列,问你这棵树是否唯一。
思路:这题真的挺好的啊,考你对递归的理解。我们知道如果已知,中序序列加前/后序序列,那么树唯一。现在已知前后序序列,那么我们想,递归到某个结点,它如果只有一个child的时候,是不是这颗树就不唯一了,因为这个child可能是左边或者右边。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 30 + 5; 4 5 struct node 6 { 7 int val; 8 node *left, *right; 9 node():left(NULL), right(NULL){} 10 }; 11 int n; 12 bool isOnlyOne; 13 int pre[maxn], post[maxn]; 14 15 node *build(int L1, int R1, int L2, int R2)//pre [L1,R1] post [L2,R2] 16 { 17 if(L1 > R1) return NULL; 18 19 node *root = new node(); 20 root->val = pre[L1]; 21 if(L1 == R1) return root; 22 int p = L1 + 1; 23 while(pre[p] != post[R2 - 1]) p++;//post[R2-1]是root右子树的根 24 int lsonSize = p - L1 - 1; 25 //此时如果没有左子树,显然不唯一。需要中序序列来维护 26 if(p == L1 + 1) 27 { 28 isOnlyOne = false; 29 root->left = NULL; 30 root->right = build(L1 + 1, R1, L2, R2 - 1); 31 } 32 else 33 { 34 root->left = build(L1 + 1, L1 + lsonSize, L2, L2 + lsonSize - 1); 35 root->right = build(p, R1, L2 + lsonSize, R2 - 1); 36 } 37 38 return root; 39 } 40 41 int cntSize;//看看已经输出几个点了 42 void in_order(node *root) 43 { 44 if(root->left != NULL) in_order(root->left); 45 cntSize++; 46 printf("%d%c", root->val, cntSize == n ? '\n' : ' '); 47 if(root->right != NULL) in_order(root->right); 48 } 49 50 int main() 51 { 52 scanf("%d", &n); 53 for(int i = 0; i < n; i++) scanf("%d", &pre[i]); 54 for(int i = 0; i < n; i++) scanf("%d", &post[i]); 55 56 isOnlyOne = true; 57 node *root = build(0, n - 1, 0, n - 1); 58 59 if(isOnlyOne) puts("Yes"); 60 else puts("No"); 61 62 cntSize = 0; 63 in_order(root); 64 return 0; 65 }
1122. Hamiltonian Cycle (25)
题意:让你判断一下这一条路径是不是哈密顿回路。
思路:判一下路上的不同的结点数,然后检测相邻两点是否图上相连就好了。模拟题。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 200 + 5; 4 5 set<int>G[maxn]; 6 int n, m; 7 int path[2000]; 8 9 int main() 10 { 11 scanf("%d%d", &n, &m); 12 for (int i = 0; i < m; i++) 13 { 14 int u, v; 15 scanf("%d%d", &u, &v); 16 G[u].insert(v); 17 G[v].insert(u); 18 } 19 20 int query; 21 scanf("%d", &query); 22 while (query --) 23 { 24 int k ; 25 scanf("%d", &k); 26 27 set<int>s; 28 for (int i = 1; i <= k; i++) 29 { 30 scanf("%d", &path[i]); 31 s.insert(path[i]); 32 } 33 int isHamiltonPath = 1; 34 if(s.size() == n && k == n + 1 && path[1] == path[k]) 35 { 36 for(int i = 2; i <= k; i++) 37 { 38 int u = path[i - 1], v = path[i]; 39 if(G[u].find(v) == G[u].end()) 40 { 41 isHamiltonPath = 0; 42 break; 43 } 44 } 45 if(isHamiltonPath) puts("YES"); 46 else puts("NO"); 47 } 48 else puts("NO"); 49 } 50 return 0; 51 }
1123. Is It a Complete AVL Tree (30)
题意:模拟avl树的插入。
思路:....课本知识
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e3 + 5; 4 5 int n, isComplete; 6 7 struct node 8 { 9 int val, height; 10 node *left, *right; 11 node():left(NULL), right(NULL){} 12 }; 13 14 int Height(node *T) 15 { 16 if(T == NULL) return -1; 17 return T->height; 18 } 19 20 node *avl_RightRotate(node *k2);//左子树的左边插入,LL旋转 需要一次右单旋 21 node *avl_LeftRightRotate(node *k3);//左子树的右边插入,LR旋转 需要一次左单旋,再一次右单旋 22 23 node *avl_LeftRotate(node *k2);//右子树的右边插入RR旋转 需要一次左单旋 24 node *avl_RightLeftRotate(node *k3);//右子树的左边插入,RL旋转 需要一次右单旋,再一次左单旋 25 26 node *avl_RightRotate(node *k2)//左子树的左边插入,LL旋转 需要一次右单旋 27 { 28 node *k1 = k2->left; 29 k2->left = k1->right; 30 k1->right = k2; 31 32 k1->height = max(Height(k1->left), Height(k1->right)) + 1; 33 k2->height = max(Height(k2->left), Height(k2->right)) + 1; 34 return k1; 35 } 36 37 38 node *avl_LeftRightRotate(node *k3)//左子树的右边插入,LR旋转 需要一次左单旋,再一次右单旋 39 { 40 k3->left = avl_LeftRotate(k3->left); 41 k3 = avl_RightRotate(k3); 42 return k3; 43 } 44 45 node *avl_LeftRotate(node *k2)//右子树的右边插入RR旋转 需要一次左单旋 46 { 47 node *k1 = k2->right; 48 k2->right = k1->left; 49 k1->left = k2; 50 51 k1->height = max(Height(k1->left), Height(k1->right)) + 1; 52 k2->height = max(Height(k2->left), Height(k2->right)) + 1; 53 return k1; 54 } 55 56 node *avl_RightLeftRotate(node *k3)//右子树的左边插入,RL旋转 需要一次右单旋,再一次左单旋 57 { 58 k3->right = avl_RightRotate(k3->right); 59 k3 = avl_LeftRotate(k3); 60 return k3; 61 } 62 63 node *avl_insert(node *T, int x) 64 { 65 if(T == NULL) 66 { 67 T = new node(); 68 T->val = x; 69 T->height = 0; 70 } 71 else if(x < T->val) 72 { 73 T->left = avl_insert(T->left, x); 74 if(Height(T->left) - Height(T->right) == 2) 75 { 76 if(x < T->left->val)//LL 77 T = avl_RightRotate(T); 78 else 79 T = avl_LeftRightRotate(T); 80 } 81 } 82 else 83 { 84 T->right = avl_insert(T->right, x); 85 if(Height(T->right) - Height(T->left) == 2) 86 { 87 if(x > T->right->val)//RR 88 T = avl_LeftRotate(T); 89 else 90 T = avl_RightLeftRotate(T); 91 } 92 } 93 T->height = max(Height(T->left), Height(T->right)) + 1; 94 return T; 95 } 96 97 void level_order(node *root) 98 { 99 queue<node*>que; 100 que.push(root); 101 int cnt = 0; 102 while(que.size()) 103 { 104 node *cur = que.front();que.pop(); 105 106 if(cur == NULL) 107 { 108 if(cnt != n) isComplete = 0; 109 continue; 110 } 111 cnt++;//非空结点计数 112 que.push(cur->left); 113 que.push(cur->right); 114 if(cur != root) printf(" "); 115 printf("%d", cur->val); 116 } 117 puts(""); 118 } 119 120 int main() 121 { 122 scanf("%d", &n); 123 node *root = NULL; 124 for (int i = 0; i < n; i++) 125 { 126 int x; 127 scanf("%d", &x); 128 root = avl_insert(root, x); 129 } 130 isComplete = 1; 131 level_order(root); 132 133 134 printf("%s\n", isComplete ? "YES" : "NO"); 135 return 0; 136 }
1127. ZigZagging on a Tree (30)
题意:序列转换
思路:....套路题。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 30 + 5; 4 5 int lch[maxn], rch[maxn], post[maxn], in[maxn], level[maxn]; 6 7 int build(int L1, int R1, int L2, int R2)//前面的是中序遍历的, 后面的是后序遍历的 8 { 9 if (L1 > R1) return -1;//你的子树已经不存在了 返回-1 10 int root = post[R2]; 11 12 int p = L1; 13 while (in[p] != root) p++; 14 int cnt = p - L1;//他的左子树有几个点 15 16 lch[root] = build(L1, p - 1, L2, L2 + cnt - 1); 17 rch[root] = build(p + 1, R1, L2 + cnt, R2 - 1); 18 return root; 19 } 20 21 void dfs(int cur, int depth) 22 { 23 level[cur] = depth; 24 int lson = lch[cur], rson = rch[cur]; 25 if (lson != -1) dfs(lson, depth + 1); 26 if (rson != -1) dfs(rson, depth + 1); 27 } 28 29 void show_post(int root) 30 { 31 int lson = lch[root], rson = rch[root]; 32 if(lson != -1) show_post(lson); 33 if(rson != -1) show_post(rson); 34 printf("%d ", root); 35 } 36 37 void show(int root, vector<int> &ans) 38 { 39 vector<int>vec; 40 queue<int>que; 41 que.push(root); 42 int d = 0; 43 while(que.size()) 44 { 45 int cur = que.front();que.pop(); 46 if(level[cur] != d) 47 { 48 if(d & 1) 49 { 50 for (int i = 0; i < vec.size(); i++) ans.push_back(vec[i]); 51 } 52 else 53 { 54 for (int i = vec.size() - 1; i >= 0; i--) ans.push_back(vec[i]); 55 } 56 d = level[cur]; 57 vec.clear(); 58 } 59 60 vec.push_back(cur); 61 int lson = lch[cur], rson = rch[cur]; 62 if (lson != -1) que.push(lson); 63 if (rson != -1) que.push(rson); 64 } 65 66 if(d & 1) 67 { 68 for (int i = 0; i < vec.size(); i++) ans.push_back(vec[i]); 69 } 70 else 71 { 72 for (int i = vec.size() - 1; i >= 0; i--) ans.push_back(vec[i]); 73 } 74 } 75 76 int main() 77 { 78 int n; 79 scanf("%d", &n); 80 for (int i = 0; i < n; i++) scanf("%d", &in[i]);//中序遍历 左根右 81 for (int i = 0; i < n; i++) scanf("%d", &post[i]);//后序遍历 左右根 82 int root = build(0, n - 1, 0, n - 1); 83 dfs(root, 0); 84 85 vector<int>ans; 86 show(root, ans); 87 for(int i = 0; i < ans.size(); i++) printf("%d%c", ans[i], i == ans.size() - 1 ? '\n' : ' '); 88 return 0; 89 }