第一次参加pat考试,结果很惨,只做了中间两道题,还有一个测试点错误,所以最终只得了不到50分。题目是甲级练习题的1148-1151。
考试时有些紧张,第一题第二题开始测试样例都运行不正确,但是调试程序考场的vs2013不能粘贴,还得一点点输上去。浪费了很多时间。
1、Werewolf - Simple Version
之前遇到这种题目较少,所以刚开始没什么思路。后来想到的方法是假设撒谎的两个人分别是i、j,然后遍历所有i、j,找出符合条件的。当时总共用了得有一个小时,但程序一直得不到正确答案,只好放弃。后来回到学校去调试程序发现问题出现在一个continue上,continue后面有一个操作需要完成但直接跳过了。但是按这个方法最后一个测试点错误。
其实这类题目问的是什么就假设什么,然后遍历所有可能性找出符合条件的就行。因此正确做法是直接假设两个狼人为i、j就行。
1 #include <iostream> 2 using namespace std; 3 4 int a[101], N; 5 int main() 6 { 7 int i, j, k, t; 8 cin >> N; 9 for (i = 1; i <= N; i++) cin >> a[i]; 10 for (i = 1; i <= N; i++) 11 { 12 for (j = i + 1; j <= N; j++) 13 { 14 bool b[101] = {}; 15 b[i] = b[j] = 1; 16 int lie1, lie2, cnt = 0; 17 for (k = 1; k <= N; k++) 18 { 19 if (a[k] > 0 && b[a[k]] || a[k] < 0 && !b[-a[k]]) 20 { 21 cnt++; 22 if (cnt == 1) lie1 = k; 23 if (cnt == 2) lie2 = k; 24 } 25 } 26 if (cnt == 2 && b[lie1] != b[lie2]) 27 { 28 printf("%d %d", i, j); 29 return 0; 30 } 31 } 32 } 33 printf("No Solution"); 34 return 0; 35 }
2、Dangerous Goods Packaging
这道题比较简单,但是考试时一开始思路不对,我用的是一个数组保存每一个编号不能放到一块的编号。但是每一个编号可能和多个编号不能放到一块,因此用set存储每一个编号的互斥编号。
1 #include <iostream> 2 #include <map> 3 #include <set> 4 using namespace std; 5 6 int main() 7 { 8 int N, M; 9 cin >> N >> M; 10 map<int, set<int>> mp; 11 int i, a, b; 12 for (i = 0; i < N; i++) 13 { 14 cin >> a >> b; 15 mp[a].insert(b); 16 mp[b].insert(a); 17 } 18 int K, j; 19 for (i = 0; i < M; i++) 20 { 21 cin >> K; 22 set<int> st; 23 bool flag = true; 24 for (j = 0; j < K; j++) 25 { 26 cin >> a; 27 if (!flag) continue; 28 if (mp.find(a) != mp.end()) 29 { 30 for (int t : mp[a]) 31 { 32 if (st.find(t) != st.end()) flag = false; 33 } 34 } 35 st.insert(a); 36 } 37 printf("%s ", flag ? "Yes" : "No"); 38 } 39 return 0; 40 }
3、Travelling Salesman Problem
这道题也不难,但是考试时有一个测试点错误,回学校后再看时发现是判断时少了一个条件,即TS cycle和TS simple cycle都要经过所有顶点。
当路径上有不相邻的顶点或者路径的首尾顶点不相连或不经过所有顶点时,Not a TS cycle。否则路径上除了最后一个顶点外有重复的顶点就是TS cycle,否则就是TS simple cycle。
1 #include <iostream> 2 using namespace std; 3 4 int G[201][201]; 5 6 int main() 7 { 8 int N, M; 9 cin >> N >> M; 10 int v, w, d, i; 11 for (i = 0; i < M; i++) 12 { 13 cin >> v >> w >> d; 14 G[v][w] = G[w][v] = d; 15 } 16 int K, n, j, first, minId, min = 99999999; 17 cin >> K; 18 for (i = 1; i <= K; i++) 19 { 20 bool na = false, simple = true, allOccured = true; 21 bool occur[201] = {}; 22 int sum = 0; 23 cin >> n >> first; 24 v = first; 25 occur[first] = true; 26 for (j = 1; j < n; j++) 27 { 28 cin >> w; 29 sum += G[v][w]; 30 if (G[v][w] == 0) na = true; 31 if (occur[w] && j != n - 1) simple = false; 32 occur[w] = true; 33 v = w; 34 } 35 for (j = 1; j <= N; j++) 36 { 37 if (!occur[j]) allOccured = false; 38 } 39 printf("Path %d: ", i); 40 if (na) printf("NA "); 41 else printf("%d ", sum); 42 if (v != first || na || !allOccured) printf("(Not a TS cycle) "); 43 else 44 { 45 if (simple) printf("(TS simple cycle) "); 46 else printf("(TS cycle) "); 47 if (sum < min) 48 { 49 min = sum; 50 minId = i; 51 } 52 } 53 } 54 printf("Shortest Dist(%d) = %d", minId, min); 55 return 0; 56 }
4、LCA in a Binary Tree
这道题开始一看还以为是原题,就按照二叉搜索树去做,最后运行结果不正确才发现题目说的是二叉树,不是二叉搜索树。但已经没时间了。
后来我用的方法是,先建树,然后求出顶点到两个节点的路径,把两个路径从前往后比较,第一个不相同结点的前一个结点就是LCA。
1 #include <iostream> 2 #include <set> 3 #include <vector> 4 using namespace std; 5 6 typedef struct Node *Tree; 7 struct Node 8 { 9 int data; 10 Tree left, right; 11 }*root; 12 13 vector<int> in, pre; 14 Tree buildTree(Tree T, int begin, int end, int root); 15 int ancestor(int u, int v); 16 bool path(Tree T, int a, vector<int>& v); 17 18 int main() 19 { 20 int M, N, i; 21 cin >> M >> N; 22 in.resize(N); 23 pre.resize(N); 24 set<int> st; 25 for (i = 0; i < N; i++) cin >> in[i]; 26 for (i = 0; i < N; i++) 27 { 28 cin >> pre[i]; 29 st.insert(pre[i]); 30 } 31 root = NULL; 32 root = buildTree(root, 0, N - 1, 0); 33 int u, v; 34 for (i = 0; i < M; i++) 35 { 36 cin >> u >> v; 37 bool b1 = (st.find(u) == st.end()); 38 bool b2 = (st.find(v) == st.end()); 39 if (b1 && b2) printf("ERROR: %d and %d are not found.", u, v); 40 else if (b1 || b2) printf("ERROR: %d is not found.", b1 ? u : v); 41 else { 42 int anc = ancestor(u, v); 43 if (anc == u) printf("%d is an ancestor of %d.", u, v); 44 else if (anc == v) printf("%d is an ancestor of %d.", v, u); 45 else printf("LCA of %d and %d is %d.", u, v, anc); 46 } 47 printf(" "); 48 } 49 return 0; 50 } 51 52 Tree buildTree(Tree T, int begin, int end, int root) 53 { 54 if (begin > end) return NULL; 55 T = new Node; 56 T->data = pre[root]; 57 T->left = T->right = NULL; 58 int p; 59 for (p = begin; p <= end; p++) 60 { 61 if (in[p] == pre[root]) break; 62 } 63 T->left = buildTree(T->left, begin, p - 1, root + 1); 64 T->right = buildTree(T->right, p + 1, end, root + p - begin + 1); 65 return T; 66 } 67 68 int ancestor(int u, int v) 69 { 70 vector<int> p1, p2; 71 bool b1 = path(root, u, p1); 72 bool b2 = path(root, v, p2); 73 int i; 74 for (i = 0; i < p1.size() && i < p2.size() && p1[i] == p2[i]; i++); 75 if (i == p1.size()) return p1[i - 1]; 76 if (i == p2.size()) return p2[i - 1]; 77 return p1[i - 1]; 78 } 79 80 bool path(Tree T, int a, vector<int>& v) 81 { 82 if (T == NULL) return false; 83 v.push_back(T->data); 84 if (T->data == a) return true; 85 bool b1 = path(T->left, a, v); 86 if (b1) return true; 87 bool b2 = path(T->right, a, v); 88 if (!b1 && !b2) 89 { 90 v.pop_back(); 91 return false; 92 } 93 return true; 94 }
看柳婼的博客学会了较简单的方法:先把每个结点在中序遍历中的位置记录下来,然后递归时根据u,v和当前root在中序遍历中的位置就可以知道u和v是在当前结点左子树还是右子树。
1 #include <iostream> 2 #include <map> 3 #include <vector> 4 using namespace std; 5 6 vector<int> in, pre; 7 map<int, int> mp; 8 9 void lca(int left, int right, int root, int u, int v); 10 11 int main() 12 { 13 int M, N, i; 14 cin >> M >> N; 15 in.resize(N + 1); 16 pre.resize(N + 1); 17 for (i = 1; i <= N; i++) 18 { 19 cin >> in[i]; 20 mp[in[i]] = i; 21 } 22 for (i = 1; i <= N; i++) cin >> pre[i]; 23 int u, v; 24 for (i = 0; i < M; i++) 25 { 26 cin >> u >> v; 27 if (mp[u] == 0 && mp[v] == 0) printf("ERROR: %d and %d are not found. ", u, v); 28 else if (mp[u] == 0 || mp[v] == 0) printf("ERROR: %d is not found. ", mp[u] ? v : u); 29 else lca(1, N, 1, u, v); 30 } 31 return 0; 32 } 33 34 void lca(int left, int right, int root, int u, int v) 35 { 36 if (left > right) return; 37 int pU = mp[u], pV = mp[v], pRoot = mp[pre[root]]; 38 if (pU < pRoot && pV < pRoot) 39 lca(left, pRoot - 1, root + 1, u, v); 40 else if (pU < pRoot && pV > pRoot || pU > pRoot && pV < pRoot) 41 printf("LCA of %d and %d is %d. ", u, v, pre[root]); 42 else if (pU > pRoot && pV > pRoot) 43 lca(pRoot + 1, right, root + pRoot - left + 1, u, v); 44 else if (pU == pRoot) 45 printf("%d is an ancestor of %d. ", u, v); 46 else if (pV == pRoot) 47 printf("%d is an ancestor of %d. ", v, u); 48 }
参加这次考试只能说明自己很菜,解题速度比较慢;审题不仔细,比如第二题开始用的一个数组去存储每个编号的互斥编号;写代码容易出现很多问题,比如第一题continue导致逻辑出现错误。
正在准备考研,时间很紧张,只能周末抽时间刷几道题,12月份冬季再参加一次。
更新:
求LCA时,用set来判断节点是否存在,当两节点都存在时,可用leetcode中的较简单的的方法:
1 #include <iostream> 2 #include <vector> 3 #include <set> 4 using namespace std; 5 6 struct Node { 7 int val; 8 Node *left, *right; 9 Node(int v) : val(v), left(NULL), right(NULL) {} 10 }*root; 11 12 vector<int> in, pre; 13 int U, V; 14 15 void buildTree(Node* &root, int b1, int b2, int e2) { 16 if (b2 > e2) return; 17 int p, t = pre[b1]; 18 root = new Node(t); 19 for (p = b2; p <= e2 && in[p] != t; p++); 20 buildTree(root->left, b1 + 1, b2, p - 1); 21 buildTree(root->right, b1 + p - b2 + 1, p + 1, e2); 22 } 23 24 Node* lca(Node* root) { 25 if (root == NULL || root->val == U || root->val == V) 26 return root; 27 Node* l = lca(root->left); 28 Node* r = lca(root->right); 29 if (l && r) return root; 30 if (l) return l; 31 return r; 32 } 33 34 int main() { 35 int M, N, i; 36 cin >> M >> N; 37 set<int> st; 38 in.resize(N); pre.resize(N); 39 for (i = 0; i < N; i++) { 40 cin >> in[i]; 41 st.insert(in[i]); 42 } 43 for (i = 0; i < N; i++) cin >> pre[i]; 44 buildTree(root, 0, 0, N - 1); 45 for (i = 0; i < M; i++) { 46 cin >> U >> V; 47 bool b1 = (st.find(U) != st.end()); 48 bool b2 = (st.find(V) != st.end()); 49 if (b1 && b2) { 50 Node* T = lca(root); 51 if (T->val == U) printf("%d is an ancestor of %d.", U, V); 52 else if (T->val == V) printf("%d is an ancestor of %d.", V, U); 53 else printf("LCA of %d and %d is %d.", U, V, T->val); 54 } 55 else if (!b1 && !b2) 56 printf("ERROR: %d and %d are not found.", U, V); 57 else if (!b1) 58 printf("ERROR: %d is not found.", U); 59 else 60 printf("ERROR: %d is not found.", V); 61 printf(" "); 62 } 63 return 0; 64 }