AtCoder Weekday Contest 0033 Beta题解(AWC 0033 Beta A-E)
D - Cheapest Commute Route
【题目来源】
AtCoder:D - Cheapest Commute Route
【题目描述】
Takahashi commutes using a railway network consisting of \(N\) stations connected by \(M\) lines. The stations are numbered from \(1\) to \(N\). Line \(i\) bidirectionally connects station \(U_i\) and station \(V_i\), with a fare of \(C_i\) yen.
高桥每天通勤使用一个由 \(N\) 个车站和 \(M\) 条线路组成的铁路网络。车站编号从 \(1\) 到 \(N\)。线路 \(i\) 双向连接车站 \(U_i\) 和车站 \(V_i\),票价为 \(C_i\) 日元。
Takahashi needs to commute every day from station \(1\), the nearest station to his home, to station \(N\), the nearest station to his workplace. Since Takahashi's transportation budget is only \(K\) yen, he must find a route whose total fare is at most \(K\) yen.
高桥每天需要从离他家最近的车站 \(1\) 通勤到离他工作地点最近的车站 \(N\)。由于高桥的交通预算只有 \(K\) 日元,他必须找到一条总票价不超过 \(K\) 日元的路线。
Here, a route refers to a path starting from station \(1\) and following lines in sequence to reach station \(N\). It is permitted to visit the same station multiple times or use the same line multiple times. The total fare of a route is the sum of the fares of all lines used in that route. If a line is used multiple times, the fare is charged for each use.
这里,路线指的是从车站 \(1\) 开始,依次沿线路行进到达车站 \(N\) 的路径。允许多次访问同一车站或多次使用同一线路
If there exists a route from station \(1\) to station \(N\) with a total fare of at most \(K\) yen, output the minimum total fare among all such routes. If no such route exists, output -1.
如果存在一条从车站 \(1\) 到车站 \(N\) 且总票价不超过 \(K\) 日元的路线,输出所有此类路线中的最小总票价。如果不存在这样的路线,输出 -1。
【输入】
\(N\) \(M\) \(K\)
\(U_1\) \(V_1\) \(C_1\)
\(U_2\) \(V_2\) \(C_2\)
\(\vdots\)
\(U_M\) \(V_M\) \(C_M\)
- The first line contains \(N\) representing the number of stations, \(M\) representing the number of lines, and \(K\) representing Takahashi's transportation budget, separated by spaces.
- From the 2nd line to the \((M + 1)\)-th line, information about the \(M\) lines is given.
- The \((1 + i)\)-th line contains the two stations \(U_i\), \(V_i\) connected by line \(i\) and the fare \(C_i\), separated by spaces.
【输出】
If there exists a route from station \(1\) to station \(N\) with a total fare of at most \(K\) yen, output the minimum total fare in one line. If no such route exists, output -1 in one line.
【输入样例】
4 4 10
1 2 3
2 4 5
1 3 7
3 4 2
【输出样例】
8
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 100005, M = 200005 * 2, INF = 1e18;
int n, m, k;
int h[N], e[M], w[M], ne[M], idx; // 邻接表
int dist[N]; // 距离数组
bool st[N]; // 访问标记
priority_queue<PII, vector<PII>, greater<PII>> heap; // 最小堆
// 添加边
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// Dijkstra算法
void dijkstra(int u)
{
// 初始化距离数组
for (int i = 1; i <= n; i++)
{
dist[i] = INF;
}
memset(st, 0, sizeof(st));
while (!heap.empty()) // 清空堆
{
heap.pop();
}
dist[u] = 0; // 源点距离为0
heap.push({0, u}); // first存储距离,second存储节点编号
while (!heap.empty())
{
auto t = heap.top();
heap.pop();
int veid = t.second, distance = t.first;
if (st[veid] == true) // 已访问过
{
continue;
}
st[veid] = true;
for (int i = h[veid]; i != -1; i = ne[i]) // 遍历邻接点
{
int j = e[i];
if (dist[j] > distance + w[i]) // 松弛操作
{
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
}
signed main()
{
cin >> n >> m >> k; // 节点数, 边数, 阈值
memset(h, -1, sizeof h);
for (int i = 1; i <= m; i++) // 建图
{
int u, v, c;
cin >> u >> v >> c;
add(u, v, c), add(v, u, c); // 无向图
}
dijkstra(1); // 从节点1开始Dijkstra
if (dist[n] > k) // 如果最短距离大于k
{
cout << -1 << endl;
}
else
{
cout << dist[n] << endl; // 输出最短距离
}
return 0;
}
【运行结果】
4 4 10
1 2 3
2 4 5
1 3 7
3 4 2
8
E - Minimum Cost of Stepping Stones
【题目来源】
AtCoder:E - Minimum Cost of Stepping Stones
【题目描述】
Takahashi is trying to cross a river. There are \(N\) stepping stones lined up in a row in the river, numbered stone \(1\), stone \(2\), \(\ldots\), stone \(N\) in order from the left bank. Takahashi starts on stone \(1\) and reaches the goal when he arrives at stone \(N\).
高桥正试图渡过一条河。河中有 \(N\) 块踏脚石排成一行,从左岸开始依次编号为石头 \(1\)、石头 \(2\)、……、石头 \(N\)。高桥从石头 \(1\) 出发,当他到达石头 \(N\) 时即到达目标。
From his current stone \(i\), Takahashi can jump to any one of stone \(i+1\), stone \(i+2\), \(\ldots\), stone \(\min(i+K,\, N)\). In other words, the difference in stone numbers covered in a single jump is between \(1\) and \(K\) inclusive, and he can only move in the direction of increasing numbers. Takahashi must land exactly on stone \(N\) at the end.
从当前所在的石头 \(i\),高桥可以跳到石头 \(i+1\)、石头 \(i+2\)、……、石头 \(\min(i+K,\, N)\) 中的任意一块。换句话说,单次跳跃跨越的石头编号差在 \(1\) 到 \(K\) 之间(含端点),且他只能朝编号增加的方向移动。高桥最终必须恰好落在石头 \(N\) 上。
Each stepping stone \(i\) \((1 \leq i \leq N)\) has a positive integer value \(A_i\) assigned to it. When Takahashi lands on a stone, that stone's value is added to the cumulative cost. The values of stones he does not land on are not added. The value \(A_1\) of the starting stone \(1\) and the value \(A_N\) of the goal stone \(N\) are also each added when he lands on them.
每块踏脚石 \(i\)(\(1 \leq i \leq N\))都有一个正整数 \(A_i\) 作为其值。当高桥落在一块石头上时,该石头的值会被累加到累计成本中。他没有踩到的石头的值不会被累加。起始石头 \(1\) 的值 \(A_1\) 和目标石头 \(N\) 的值 \(A_N\) 也会在他落在上面时分别被累加。
Among all paths Takahashi can take from stone \(1\) to stone \(N\), find the one that minimizes the cumulative cost, and output that minimum cumulative cost.
在高桥从石头 \(1\) 到石头 \(N\) 的所有可行路径中,找出使累计成本最小化的路径,并输出该最小累计成本。
【输入】
\(N\) \(K\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
- The first line contains an integer \(N\) representing the number of stepping stones and an integer \(K\) representing the maximum difference in stone numbers that can be covered in a single jump, separated by a space.
- The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the values of each stepping stone, separated by spaces.
【输出】
Output in one line the minimum cumulative cost when traveling from stone \(1\) to stone \(N\).
【输入样例】
5 2
1 3 2 4 1
【输出样例】
4
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005, INF = 1e18;
int n, k;
int a[N], dp[N]; // a: 代价数组, dp: 动态规划数组
struct Node
{
int v, idx; // v: 值, idx: 索引
};
deque<Node> dq; // 单调队列
signed main()
{
scanf("%d %d", &n, &k); // 输入数组长度和跳跃距离限制
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]); // 输入每个位置的代价
}
for (int i = 1; i <= n; i++) // 初始化dp数组
{
dp[i] = INF;
}
dp[1] = a[1]; // 起点代价
dq.push_back({dp[1], 1}); // 将起点加入队列
for (int i = 2; i <= n; i++)
{
// 移除超出窗口范围的元素
while (!dq.empty() && dq.front().idx < i - k)
{
dq.pop_front();
}
// 转移方程:dp[i] = min{dp[j]} + a[i] (i-k ≤ j < i)
dp[i] = dq.front().v + a[i];
// 维护队列单调递增
while (!dq.empty() && dq.back().v >= dp[i])
{
dq.pop_back();
}
dq.push_back({dp[i], i}); // 将当前元素加入队列
}
cout << dp[n] << endl; // 输出到达终点的最小总代价
return 0;
}
【运行结果】
5 2
1 3 2 4 1
浙公网安备 33010602011771号