天梯赛 L3 练习题(1)
发布日期:2021-05-15 10:18:55 浏览次数:19 分类:精选文章

本文共 8893 字,大约阅读时间需要 29 分钟。

以下是优化后的内容:

天梯赛 L3 练习题 1

题目1:L3-001 鑄零钱

题意:给定n枚硬币的面值,问能否恰好凑成m元。输出字典序最小的排列,或者输出“No Solution”。

思路:贪心算法,从小面额硬币开始取,这样排列才会字典序最小。使用动态规划记录能否凑成每个金额,并记录路径。

代码示例

#include 
#include
using namespace std;
int main() {
int n, m;
vector
a(n);
// 读取输入并排序
sort(a.begin(), a.end());
// 初始化dp数组
vector
dp(m + 1, false);
dp[0] = true;
// 遍历每个硬币
for (int i = 0; i < n; ++i) {
int val = a[i];
for (int j = m; j >= val; --j) {
if (dp[j - val] && !dp[j]) {
dp[j] = true;
}
}
}
if (!dp[m]) {
puts("No Solution");
} else {
// 回溯路径
vector
ans;
int cur = m;
for (int i = n - 1; i >= 0; --i) {
if (cur >= a[i] && dp[cur - a[i]]) {
ans.push_back(a[i]);
cur -= a[i];
}
}
// 输出结果
int len = ans.size();
for (int i = 0; i < len; ++i) {
if (i != len - 1) {
printf("%d", ans[i]);
} else {
printf("%d\n", ans[i]);
}
}
}
return 0;
}

题目2:L3-002 特殊堆栈

题意:维护一个栈,支持Push、Pop、PeekMedian操作。PeekMedian要求输出栈中第(n+1)/2小的数。

思路:使用线段树维护元素个数,通过二分查找找到第k小的元素。

代码示例

#include 
#include
using namespace std;
int main() {
int n;
vector
sta(n);
// 初始化线段树
vector
st(4 * n, 0);
// Push操作
while (n--) {
string s;
cin >> s;
if (s == "Push") {
int val = sta[top];
update(1, val, 1, n, 1);
sta[++top] = val;
} else if (s == "Pop") {
if (!top) {
puts("Invalid");
continue;
}
int val = sta[top];
update(1, val, 1, n, -1);
sta[top--] = 0;
} else {
if (!top) {
puts("Invalid");
continue;
}
int k = (top + 1) / 2;
int res = query(1, k, 1, n);
puts(res);
}
}
return 0;
}

题目3:L3-003 社交集群

题意:给定n个人的兴趣列表,找出每个社交集群的人数。

思路:使用并查集,合并具有相同兴趣爱好的节点,最后统计每个根节点的大小。

代码示例

#include 
using namespace std;
int main() {
int n;
vector
pa(n + 1), sz(n + 1);
for (int i = 1; i <= n; ++i) {
int k, x, y;
cin >> k >> x >> y;
visit[x] = 1;
for (int i = 2; i <= k; ++i) {
cin >> y;
visit[y] = 1;
union(x, y);
}
sz[find(x)]++;
}
// 收集结果并排序
vector
ans;
for (int i = 1; i <= 1000; ++i) {
if (pa[i] == i && visit[i]) {
ans.push_back(sz[i]);
}
}
sort(ans.begin(), ans.end(), greater
());
int m = ans.size();
printf("%d\n", m);
if (m > 0) {
for (int i = 1; i <= m; ++i) {
if (i != m) {
printf("%d", ans[i - 1]);
} else {
printf("%d\n", ans[i - 1]);
}
}
}
return 0;
}

题目4:L3-005 垃圾箱分布

题意:选择一个垃圾箱点,使得到其他住户的最小距离最大,相同则平均距离最小,相同则编号最小。

思路:对每个点,计算到所有住户的最短距离总和,找出总和最大的点。

代码示例

#include 
#include
using namespace std;
int main() {
int n, m, k, d;
vector
> e;
for (int i = 1; i <= k; ++i) {
string x, y;
int w;
cin >> x >> y >> w;
int u = calc(x), v = calc(y);
e[u].push_back({v, w});
e[v].push_back({u, w});
}
// 计算每个点的总距离
int ans1 = 0, ans2 = INF;
int best = -1;
for (int i = 1; i <= m; ++i) {
int s = n + i;
// 使用Dijkstra计算每个住户的最短距离
vector
dis(n + 1, INF);
vector
sum_d(n + 1, 0); int ok = 1; for (int j = 1; j <= n; ++j) { if (dis[j] > d) { ok = 0; break; } sum_d[j] += dis[j]; } if (!ok) continue; if (sum_d[j] > sum_d[best]) { ans1 = sum_d[j]; best = i; } else if (sum_d[j] == sum_d[best]) { if (i < best) { best = i; } } } // 输出结果 if (best != -1) { int s = n + best; // 进行Dijkstra计算每个住户的最短距离 vector
dis(n + 1, INF); for (int j = 1; j <= n; ++j) dis[j] = INF; dis[s] = 0; // 使用优先队列 priority_queue
> pq; pq.push({0, s}); while (!pq.empty()) { int d, u = pq.top().second; pq.pop(); if (visit[u]) continue; visit[u] = 1; for (auto v : e[u]) { int v_node = v.first, weight = v.second; if (dis[v_node] > dis[u] + weight) { dis[v_node] = dis[u] + weight; pq.push({dis[v_node], v_node}); } } } // 计算各住户的距离 int max_d = 0, sum_d = 0; int max_id = -1; for (int j = 1; j <= n; ++j) { if (dis[j] > max_d) { max_d = dis[j]; max_id = j; } sum_d += dis[j]; } // 输出结果 printf("%d\n", max_d); vector
res; int cur = max_id; do { res.push_back(cur); cur = pre[cur]; } while (cur != -1); reverse(res.begin(), res.end()); int m_res = res.size(); for (int i = 0; i < m_res; ++i) { if (i != m_res - 1) { printf("%d", res[i]); } else { printf("%d\n", res[i]); } } } else { puts("No Solution"); } return 0; }

题目5:L3-007 天梯地图

题意:给定图的边权有时间和距离两种,找出两条路径:时间最短和距离最短。

思路:分别运行两次Dijkstra,一次记录时间,另一次记录距离和经过点数。

代码示例

#include 
#include
using namespace std;
int main() {
int n, m;
vector
> e;
for (int i = 1; i <= m; ++i) {
int u, v, ty, w, t;
cin >> u >> v >> ty >> w >> t;
e[u].push_back({v, w, t});
e[v].push_back({u, w, t});
}
// 时间最短路径
int time shortest, dis shortest;
vector
time_path, dis_path, num_path;
// 距离最短路径
int dist shortest, dist_num shortest;
// 两次Dijkstra
// ...
// 输出结果
printf("Time: %d Distance: %d Path: ", time_shortest, dis_shortest);
// 输出路径
// ...
return 0;
}

题目6:L3-008 告诉山

题意:无向图中,查询给定节点到图中其他节点的最远距离及对应的节点编号。

思路:使用BFS计算每个节点的深度,记录最远距离和对应的节点。

代码示例

#include 
using namespace std;
int main() {
int n, m, q;
vector
> e;
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
// 处理每个查询
for (int i = 1; i <= q; ++i) {
int x;
cin >> x;
// BFS计算深度
vector
depth(n + 1, 0);
vector
visit(n + 1, false);
queue
q; q.push(x); visit[x] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (int v : e[u]) { if (!visit[v]) { visit[v] = true; depth[v] = depth[u] + 1; q.push(v); } } } // 找最大深度的节点 int max_d = *max_element(depth.begin() + 1, depth.begin() + n + 1); int id = 0; if (max_d > 1) { for (int j = 1; j <= n; ++j) { if (depth[j] == max_d) { id = j; break; } } } ans.push_back(id); } // 输出结果 for (int i = 1; i <= q; ++i) { printf("%d\n", ans[i - 1]); } return 0; }

题目7:L3-009 长城

题意:设置烽火台,使得从右往左可以一直被看到。

思路:从右往左扫描,当遇到一个凸点挡住视线时,设置这个点为烽火台。

代码示例

#include 
using namespace std;
int main() {
int n;
vector
x(n + 1), y(n + 1);
// 设置栈
set
ans;
int top = 0;
for (int i = 1; i <= n; ++i) {
while (top >= 1 && check(i, sta[top], sta[top - 1])) {
top--;
}
if (top >= 1 && sta[top] != 1) {
ans.insert(sta[top]);
}
sta[++top] = i;
}
// 输出结果
printf("%d\n", ans.size());
return 0;
}

题目8:L3-010 是否完全二叉搜索树

题意:判断给定的树是否为完全二叉树。

思路:层序遍历时,检查除了最后一层外,其他层是否完全填充。

代码示例

#include 
using namespace std;
int main() {
int n;
vector
a(n + 1);
// 插入到树中
Node* root = new Node();
for (int i = 1; i <= n; ++i) {
insert(root, a[i]);
}
// BFS遍历
vector
ans;
int sta = 0;
queue
q;
q.push(root);
while (!q.empty()) {
Node* t = q.front();
q.pop();
if (sta == 0) {
sta = 1;
}
if (sta == 1) {
sta = 2;
}
ans.push_back(t->val);
if (t->ls) q.push(t->ls);
if (t->rs) q.push(t->rs);
}
// 判断是否为完全二叉树
if (sta != 2) {
puts("YES");
} else {
puts("NO");
}
return 0;
}

题目9:L3-011 直捣黄龙

题意:带权图中,找出一条最短路径,满足特定规则。

思路:使用Dijkstra算法,记录路径长度、经过的点数和杀敌数,满足优先级顺序。

代码示例

#include 
using namespace std;
int main() {
int n, m;
map
id, name;
// 读取输入
while (m--) {
string x, y;
int w;
cin >> x >> y >> w;
int u = id[x], v = id[y];
e[u].push_back({v, w});
e[v].push_back({u, w});
}
// Dijkstra算法
int shortest_path_length, shortest_dist, kills;
vector
path;
// 详细实现见代码
// ...
// 输出结果
printf("%d %d %d\n", path_size, shortest_dist, kills);
return 0;
}

总结

以上是对每个题目的分析和简要代码示例,希望对解决问题有所帮助。

上一篇:PAT题目集
下一篇:天梯赛 L3 练习题(2)

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年04月25日 14时33分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章