《挑战程序设计竞赛》课后练习题解集——2.4 加工并存储数据的数据结构

↘锁芯ラ 提交于 2020-01-20 20:54:24

2.4 加工并存储数据的数据结构

优先队列

 

POJ 3614  C个cow各需要一定范围的SPF防晒霜,给出L种防晒霜及其数量,求最大能满足多少cow的需要

按右端点排序,优先使用SPF小的防晒霜

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <queue>
 4 using namespace std;
 5 #define P pair<int, int>
 6 
 7 int num[1005];
 8 
 9 int main() {
10     ios::sync_with_stdio(false);
11     int c, l, x, y;
12     cin >> c >> l;
13     priority_queue<P, vector<P>, greater<P> > que;
14     for (int i = 0; i < c; i++) {
15         cin >> x >> y;
16         que.push(P(y, x));
17     }
18     for (int i = 0; i < l; i++) {
19         cin >> x >> y;
20         num[x] += y;
21     }
22     int r = 0;
23     while (!que.empty()) {
24         int a = que.top().second, b = que.top().first;
25         for (int i = a; i <= b; i++) {
26             if (num[i]) {
27                 num[i]--;
28                 r++;
29                 break;
30             }
31         }
32         que.pop();
33     }
34     cout << r;
35 }
View Code

 

POJ 2010  C个元素(具有分数和代价),选取N(奇数)个,使得代价不超过F且分数的中位数尽可能大

枚举中位数,从前一部分和后一部分分别选出代价最小的(N-1)个。而相邻中位数这一信息是可以log N转移的

 1 #include <algorithm>
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <queue>
 5 #include <set>
 6 #include <vector>
 7 #include <cstdlib>
 8 using namespace std;
 9 #define ll long long
10 #define pii pair<int, int>
11 #define fi first
12 #define se second
13 #define pb push_back
14 
15 const int maxn = 1e5 + 5;
16 
17 int n, c, f, pos1, pos2;
18 ll tmp;
19 
20 struct node {
21     int sc, val;
22     bool operator<(const node &o) const { return sc > o.sc; }
23 } a[maxn];
24 
25 priority_queue<int> pque1;
26 priority_queue<int, vector<int>, greater<int> > pque2;
27 
28 ll tot[maxn];
29 
30 int main() {
31     scanf("%d %d %d", &n, &c, &f);
32     for (int i = 0; i < c; i++) {
33         scanf("%d %d", &a[i].sc, &a[i].val);
34     }
35     sort(a, a + c);
36     pos1 = n / 2, pos2 = c - pos1 - 1;
37     for (int i = pos1; i <= pos2; i++) tot[i] = a[i].val;
38     for (int i = 0; i < pos1; i++) {
39         tmp += a[i].val;
40         pque1.push(a[i].val);
41     }
42     tot[pos1] += tmp;
43     for (int i = pos1 + 1; i <= pos2; i++) {
44         pque2.push(a[i - 1].val);
45 
46         tmp -= pque1.top();
47         pque2.push(pque1.top());
48         pque1.pop();
49 
50         tmp += pque2.top();
51         pque1.push(pque2.top());
52         pque2.pop();
53 
54         tot[i] += tmp;
55     }
56     while (!pque1.empty()) pque1.pop();
57     while (!pque2.empty()) pque2.pop();
58     tmp = 0;
59     for (int i = pos2 + 1; i < c; i++) {
60         tmp += a[i].val;
61         pque1.push(a[i].val);
62     }
63     tot[pos2] += tmp;
64     for (int i = pos2 - 1; i >= pos1; i--) {
65         pque2.push(a[i + 1].val);
66 
67         tmp -= pque1.top();
68         pque2.push(pque1.top());
69         pque1.pop();
70 
71         tmp += pque2.top();
72         pque1.push(pque2.top());
73         pque2.pop();
74 
75         tot[i] += tmp;
76     }
77 
78     for (int i = pos1; i <= pos2; i++) {
79         if (tot[i] <= f) {
80             printf("%d\n", a[i].sc);
81             exit(0);
82         }
83     }
84     printf("-1\n");
85 }
View Code

 

 并查集

 

POJ 2236  N个节点,对某一节点操作可以修复该节点,已修复节点之间的距离在d以内时是可联系的,联系具有传递性;查询两个节点能否联系 

修复一个节点时,遍历其他其它节点,如果在距离以内且已修复就用并查集并在一起

 1 #include <cmath>
 2 #include <iostream>
 3 using namespace std;
 4 #define P pair<int, int>
 5 
 6 const double eps = 1e-8;
 7 
 8 P point[1001];
 9 int vis[1001], par[1001], ran[1001];
10 
11 void init(int x) {
12     for (int i = 1; i <= x; i++) {
13         par[i] = i;
14     }
15 }
16 
17 int find(int x) {
18     if (x == par[x]) return x;
19     return par[x] = find(par[x]);
20 }
21 
22 void unite(int x, int y) {
23     x = find(x);
24     y = find(y);
25     if (x == y) return;
26     if (ran[x] < ran[y])
27         par[x] = y;
28     else {
29         par[y] = x;
30         if (ran[x] == ran[y]) ran[x]++;
31     }
32 }
33 
34 bool same(int x, int y) { return find(x) == find(y); }
35 
36 int main() {
37     ios::sync_with_stdio(false);
38     int d, n, x, y;
39     cin >> n >> d;
40     init(n);
41     for (int i = 1; i <= n; i++) {
42         cin >> point[i].first >> point[i].second;
43     }
44     char c;
45     while (cin >> c) {
46         if (c == 'O') {
47             cin >> x;
48             if (vis[x] == 1) continue;
49             vis[x] = 1;
50             int xi = point[x].first, yi = point[x].second;
51             for (int i = 1; i <= n; i++) {
52                 if (vis[i] &&
53                     (xi - point[i].first) * (xi - point[i].first) +
54                             (yi - point[i].second) * (yi - point[i].second) <=
55                         d * d) {
56                     unite(x, i);
57                 }
58             }
59         } else {
60             cin >> x >> y;
61             if (same(x, y))
62                 cout << "SUCCESS\n";
63             else
64                 cout << "FAIL\n";
65         }
66     }
67 }
View Code

 

POJ 1703  N个人,给出M条信息,可以确认其中两人是否是同一阵营;查询两个人是否是同一阵营

弱化版的食物链

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 int par[200001], ran[200001];
 7 
 8 void init(int x) {
 9     for (int i = 1; i <= x; i++) {
10         par[i] = i;
11         ran[i] = 0;
12     }
13 }
14 
15 int find(int x) {
16     if (x == par[x]) return x;
17     return par[x] = find(par[x]);
18 }
19 
20 void unite(int x, int y) {
21     x = find(x);
22     y = find(y);
23     if (x == y) return;
24     if (ran[x] < ran[y])
25         par[x] = y;
26     else {
27         par[y] = x;
28         if (ran[x] == ran[y]) ran[x]++;
29     }
30 }
31 
32 bool same(int x, int y) { return find(x) == find(y); }
33 
34 int main() {
35     ios::sync_with_stdio(false);
36     int t, n, m, x, y;
37     char ch[2];
38     scanf("%d", &t);
39     while (t--) {
40         scanf("%d%d", &n, &m);
41         init(2 * n);
42         while (m--) {
43             scanf("%s%d%d", ch, &x, &y);
44             if (ch[0] == 'D') {
45                 unite(x, y + n);
46                 unite(x + n, y);
47             } else {
48                 if (same(x, y))
49                     cout << "In the same gang.\n";
50                 else if (same(x, y + n))
51                     cout << "In different gangs.\n";
52                 else
53                     cout << "Not sure yet.\n";
54             }
55         }
56     }
57 }
View Code

 

AOJ 2170  一棵树,给某一点打标记,查询一个节点最近的打过标记的祖先

打标记时,把双亲节点改为自身,查询时往上走。最坏时间复杂度是O(N^2),没有T,大概率是数据问题

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int par[100005];
 5 
 6 int main() {
 7     ios::sync_with_stdio(false);
 8     int n, q, x;
 9     char s[2];
10     par[1] = 1;
11     while (scanf("%d%d", &n, &q) != EOF) {
12         if (n == 0 && q == 0) break;
13         for (int i = 2; i <= n; i++) scanf("%d", &par[i]);
14         long long sum = 0;
15         for (int i = 0; i < q; i++) {
16             scanf("%s%d", s, &x);
17             if (s[0] == 'Q') {
18                 while (x != par[x]) x = par[x];
19                 sum += x;
20             } else {
21                 par[x] = x;
22             }
23         }
24         cout << sum << "\n";
25     }
26 }
View Code

 

END

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!