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 }

 

posted @ 2017-03-21 19:45  luosuo10  阅读(1411)  评论(0编辑  收藏  举报