这里是paoxiaomo,一个现役ACMer,之后将会持续更新算法笔记系列以及笔试题题解系列
本文章面向想打ICPC/蓝桥杯/天梯赛等程序设计竞赛,以及各个大厂笔试的选手
感谢大家的订阅➕ 和 喜欢💗
有什么想看的算法专题可以私信博主
(本文题面由清隆学长收集)
01.扑克牌消消乐
题目描述
K小姐最近沉迷于一款扑克牌消除游戏。游戏规则如下:从一副扑克牌中随机抽取 n n n 张牌组成一个序列,如果有连续的 3 3 3 张相同牌号的卡牌,则这 3 3 3 张卡牌可以消除。消除后,剩余卡牌按照当前顺序重新合并成新的序列,继续寻找可以消除的卡牌组合,直到无法再消除为止。
需要注意的是,如果存在连续的 4 4 4 张相同牌号的卡牌,在消除后会剩余 1 1 1 张该牌号的卡牌。
现在,K小姐想知道最后剩余的卡牌序列是什么样的,你能帮助她吗?
输入格式
第一行包含一个正整数 n n n( 1 ≤ n ≤ 52 1 \leq n \leq 52 1≤n≤52),表示抽取的卡牌数量。
第二行包含 n n n 个以空格分隔的字符串,表示抽取的卡牌序列,卡牌号仅包含 2 2 2- 10 10 10, A A A, J J J, Q Q Q, K K K。
输出格式
输出一个字符串,表示最终剩余的卡牌号序列,卡牌号之间以空格分隔。如果最终没有卡牌剩余,则输出 0 0 0。
样例输入
10
3 A 2 2 2 A A 7 7 7
样例输出
3
数据范围
- 1 ≤ n ≤ 52 1 \leq n \leq 52 1≤n≤52
- 卡牌号仅包含 2 2 2- 10 10 10, A A A, J J J, Q Q Q, K K K。
【题目解析】
- 读取输入,包括卡牌数量 n n n 和 n n n 张卡牌序列。
- 定义一个函数
removeTriples
,用于消除连续 3 3 3 张相同牌号的卡牌,并返回消除后的卡牌序列。 - 进入主循环,不断调用
removeTriples
函数直到无法再消除为止,即当前序列与上一次序列相同。 - 输出最终剩余的卡牌序列,如果没有剩余卡牌则输出 "0"。
其中 removeTriples
函数负责消除连续 3 3 3 张相同牌号的卡牌:
cpp
cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string removeTriples(const string& cards) {
string result = "";
int len = cards.length();
int i = 0;
while (i < len) {
int j = i;
while (j < len && cards[j] == cards[i]) {
j++;
}
if (j - i >= 3) {
i = j;
} else {
result += cards.substr(i, j - i);
i = j;
}
}
return result;
}
int main() {
int n;
cin >> n;
vector<string> cards(n);
for (int i = 0; i < n; ++i) {
cin >> cards[i];
}
string current = "";
for (int i = 0; i < n; ++i) {
current += cards[i];
}
string prev = "";
while (prev != current) {
prev = current;
current = removeTriples(current);
}
if (current.empty()) {
cout << "0" << endl;
} else {
for (char c : current) {
cout << c << " ";
}
cout << endl;
}
return 0;
}
02.公司部门风险评估
题目描述
LYA 是一家大型科技公司的风险评估师。公司的部门结构可以看作一棵树,每个部门在评估前都有一些尚未解决的问题。部门的风险值可以用来评估该部门是否存在风险,风险值的计算公式为: 风险值 = 5 × 严重问题数 + 2 × 一般问题数 风险值 = 5 \times 严重问题数 + 2 \times 一般问题数 风险值=5×严重问题数+2×一般问题数。
其中,每个部门的不同级别问题数量需要将该部门及其下属部门的相应级别问题数量求和。当部门的风险值小于等于给定的阈值时,该部门被认为是安全的;否则,该部门被视为风险部门,需要进一步整改。
现在给出公司的部门结构以及各部门的问题数量,请你帮助 LYA 计算出风险部门的数量。
输入格式
第一行包含两个正整数 M M M 和 N N N( 1 ≤ M ≤ 100000 1 \leq M \leq 100000 1≤M≤100000, 1 ≤ N ≤ 1000 1 \leq N \leq 1000 1≤N≤1000),分别表示风险阈值和部门的数量。
接下来 N N N 行,每行包含四个字段,用空格分隔:
- 第一个字段为部门名称 A i A_i Ai;
- 第二个字段为 A i A_i Ai 的上级部门名称 B i B_i Bi,如果 A i A_i Ai 为公司的最高层部门,则 B i B_i Bi 用
*
表示; - 第三个字段为问题级别 C i C_i Ci( C i ∈ { 0 , 1 } C_i \in \{0, 1\} Ci∈{0,1},其中 0 0 0 表示严重问题, 1 1 1 表示一般问题);
- 第四个字段为该部门该级别的问题数量 D i D_i Di( 1 ≤ D i ≤ 1000 1 \leq D_i \leq 1000 1≤Di≤1000)。
其中, A i A_i Ai 和 B i B_i Bi 为由小写英文字母组成的字符串,长度不超过 5 5 5。
输入保证部门结构为一棵树,不会出现环的情况。
输出格式
输出一个整数,表示风险部门的数量。
样例输入
40 12
a * 0 2
a * 1 2
b a 0 3
b a 1 5
c a 1 3
d a 0 1
d a 1 3
e b 0 2
f * 0 8
f * 1 10
g f 1 2
h * 0 4
样例输出
2
数据范围
- 1 ≤ M ≤ 100000 1 \leq M \leq 100000 1≤M≤100000
- 1 ≤ N ≤ 1000 1 \leq N \leq 1000 1≤N≤1000
- 1 ≤ D i ≤ 1000 1 \leq D_i \leq 1000 1≤Di≤1000
- A i A_i Ai 和 B i B_i Bi 为由小写英文字母组成的字符串,长度不超过 5 5 5。
【题目解析】
- 读取输入,包括风险阈值和部门数量,并构建部门树结构。
- 对每个部门,计算其风险值,如果风险值大于阈值,则该部门及其下属部门都被标记为风险部门。
- 统计所有被标记的部门数量,即为风险部门的数量。
- 输出风险部门的数量。
cpp
cpp
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
struct Department {
string name;
string parent;
int severe_issues;
int normal_issues;
vector<string> children;
};
unordered_map<string, Department> departments;
// Function to calculate the risk value of a department
int calculateRisk(const string& department_name, int threshold) {
Department& dept = departments[department_name];
int risk_value = 5 * dept.severe_issues + 2 * dept.normal_issues;
if (risk_value > threshold) {
return 1;
} else {
int total_risk = 0;
for (const string& child_name : dept.children) {
total_risk += calculateRisk(child_name, threshold);
}
return total_risk;
}
}
int main() {
int threshold, num_departments;
cin >> threshold >> num_departments;
for (int i = 0; i < num_departments; ++i) {
string name, parent;
int issue_type, num_issues;
cin >> name >> parent >> issue_type >> num_issues;
departments[name] = {name, parent, 0, 0};
if (issue_type == 0) {
departments[name].severe_issues = num_issues;
} else {
departments[name].normal_issues = num_issues;
}
if (parent != "*") {
departments[parent].children.push_back(name);
}
}
int risk_departments = calculateRisk("*", threshold);
cout << risk_departments << endl;
return 0;
}
03.城市应急疏散
题目描述
LYA 是一名城市应急管理专家,她负责制定城市在发生重大事故时的疏散计划。城市由 n n n 个区域组成,每个区域之间都有道路相连。当某个区域发生事故需要疏散时,LYA 需要选择一个或多个安全区域作为疏散目的地,并确保疏散路径的总长度最短。
给定一个 n × n n \times n n×n 的矩阵 d i s t dist dist,其中 d i s t [ i ] [ j ] dist[i][j] dist[i][j] 表示区域 i i i 到区域 j j j 的道路长度,如果 d i s t [ i ] [ j ] = − 1 dist[i][j] = -1 dist[i][j]=−1,则表示区域 i i i 和区域 j j j 之间没有直接相连的道路。另外,每个区域还有一个剩余容量 c a p [ i ] cap[i] cap[i],表示该区域最多可以容纳的人数。
当某个区域 x x x 发生事故需要疏散人数为 p p p 时,请你帮助 LYA 选择疏散区域,使得疏散路径的总长度最短,并且疏散区域的剩余容量之和不小于 p p p。如果有多个疏散区域到事故区域的最短路径长度相同,则优先选择编号较小的区域。
输入格式
第一行包含一个正整数 n n n,表示区域的数量。
接下来 n n n 行,每行包含 n n n 个整数,表示矩阵 d i s t dist dist。
接下来一行包含 n n n 个整数,表示每个区域的剩余容量 c a p [ i ] cap[i] cap[i]。
最后一行包含两个整数 x x x 和 p p p,分别表示发生事故的区域编号和需要疏散的人数。
输出格式
输出一行,包含若干个整数,表示选择的疏散区域编号。如果有多个疏散区域到事故区域的最短路径长度相同,则按照编号从小到大的顺序输出。
样例输入
4
-1 5 -1 8
5 -1 1 3
-1 1 -1 4
8 3 4 -1
10 20 15 25
2 12
样例输出
1
数据范围
- 2 ≤ n ≤ 1 0 4 2 \leq n \leq 10^4 2≤n≤104
- − 1 ≤ d i s t [ i ] [ j ] ≤ 1000 -1 \leq dist[i][j] \leq 1000 −1≤dist[i][j]≤1000
- 1 ≤ c a p [ i ] ≤ 100 1 \leq cap[i] \leq 100 1≤cap[i]≤100
- 0 ≤ x < n 0 \leq x < n 0≤x<n
- 0 < p ≤ 1000 0 < p \leq 1000 0<p≤1000
【题目解析】
- 读取输入,包括区域数量、区域之间的道路长度矩阵、每个区域的剩余容量、发生事故的区域编号以及需要疏散的人数。
- 使用 Dijkstra 算法计算发生事故的区域到每个其他区域的最短路径长度。
- 遍历所有区域,对于每个区域,检查其剩余容量是否大于等于需要疏散的人数,并且计算到事故区域的最短路径长度。
- 如果满足条件,则将该区域加入备选疏散区域列表中。
- 在备选疏散区域列表中选择路径长度最短的区域作为疏散目的地。
- 输出选择的疏散区域编号。
cpp
cpp
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
const int INF = INT_MAX;
// Structure to represent a city node
struct Node {
int id;
int capacity;
};
// Structure to represent an edge between two nodes
struct Edge {
int to;
int weight;
};
// Dijkstra algorithm to find shortest paths from a source node to all other nodes
vector<int> dijkstra(const vector<vector<Edge>>& graph, int source) {
int n = graph.size();
vector<int> dist(n, INF);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, source});
dist[source] = 0;
while (!pq.empty()) {
int u = pq.top().second;
int d = pq.top().first;
pq.pop();
if (d > dist[u]) continue;
for (const Edge& e : graph[u]) {
int v = e.to;
int w = e.weight;
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
return dist;
}
int main() {
int n;
cin >> n;
vector<vector<Edge>> graph(n, vector<Edge>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int length;
cin >> length;
if (length != -1) {
graph[i].push_back({j, length});
}
}
}
vector<Node> nodes(n);
for (int i = 0; i < n; ++i) {
cin >> nodes[i].capacity;
}
int x, p;
cin >> x >> p;
x--; // Adjusting 1-based indexing to 0-based indexing
// Find shortest paths from the accident node
vector<int> shortest_paths = dijkstra(graph, x);
// Find evacuation nodes
vector<int> evacuation_nodes;
for (int i = 0; i < n; ++i) {
if (i != x && nodes[i].capacity >= p && shortest_paths[i] != INF) {
evacuation_nodes.push_back(i);
}
}
// Sort evacuation nodes based on shortest paths
sort(evacuation_nodes.begin(), evacuation_nodes.end(), [&](int a, int b) {
return shortest_paths[a] < shortest_paths[b];
});
// Output selected evacuation nodes
for (int i = 0; i < evacuation_nodes.size(); ++i) {
cout << evacuation_nodes[i] + 1 << " "; // Adjusting back to 1-based indexing
}
cout << endl;
return 0;
}
整理试题不易,你的关注是我更新的最大动力!关注博主 带你看更多面试及竞赛试题和实用