题解:P14307 【MX-J27-T4】点灯
woshi_dabian · · 题解
update 2025/10/26 接受了大佬们的建议,将新渲染框设置为默认打开(代码框除外)。并给每一层添加了清晰概括便于学习。
注:本题解有层层剖析部分,在总结中也有传统题解风格,可以自由选择。由于本题是典型的分层图最短路题,故讲解详细,适于新手初学分层图。
让我们一层一层剥开这道题!
零楼:读懂题目
::::success[题意解析]{open}
给定一个
一楼:解题方向
::::info[问]{open}
怎样判断起点到一个点是否存在长度为
二楼:分层图的引入
::::info[问]{open}
如何分别求出奇偶最短路?怎样处理边的限制?
::::
::::warning[答1]{open}
我们引入分层图。定义
Q.push((node1){1, 0});
while (Q.size()) {
t = Q.top();
Q.pop();
tu = t.u;
tw = t.w;
if (book[tu][tw % 2]) continue;
book[tu][tw % 2] = 1;
for (int i = 0; i < V[tu].size(); i++) {
tw = t.w;
tv = V[tu][i].v;
if (tw < V[tu][i].w) {
tw += ((V[tu][i].w - tw) / 2) * 2;
if (tw < V[tu][i].w) tw += 2;
}
tw++;
if (dis[tv][tw % 2] > tw) {
dis[tv][tw % 2] = tw;
Q.push((node1){tv, tw, tw % 2});
}
}
}
::::
三楼:答案获取
::::info[问]{open} 在获得奇偶最短路后,如何利用其找出答案? :::: ::::warning[答]{open} 只需要分别统计到达各个点奇数最短路中的最大值和偶数最短路中的最大值,再在二者中取最小值。
原因在一楼有讲,通过回退再回来使长度和最长路径一样。而最长路径就是满足各个点通过回退能到达的最小值。 ::::
四楼:无解判断
::::info[问]{open} 什么情况下会无解? :::: ::::warning[答]{open} 常规情况是奇数最短路和偶数最短路中都存在无法到达的点,因此无解。
特殊情况是由于起点开始时无法回退,若与起点相连的每一条边天数限制都大于
跳楼:AC此题
::::success[总结]{open}
核心算法:分层图最短路。由于到达每个点可以通过路途中回退再回来使得路径长度增加
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2.5e4 + 10;
struct node{
ll v, w;
};
vector<node> V[N];
ll dis[N][2], book[N][2];
struct node1{
ll u, w, op;
bool operator<(const node1 x) const{
return w > x.w;
}
};
priority_queue<node1> Q;
int main() {
ll c, T;
scanf("%lld%lld", &c, &T);
ll n, m, o, u, v, w;
node1 t;
ll tu, tv, tw, ans, minn, flag;
while (T--) {
scanf("%lld%lld%lld", &n, &m, &o);
for (int i = 1; i <= n; i++) V[i].clear();
flag = 0;
for (int i = 1; i <= m; i++) {
scanf("%lld%lld%lld", &u, &v, &w);
w--;
if ((u == 1 || v == 1) && w == 0) flag = 1;
V[u].push_back((node){v, w});
V[v].push_back((node){u, w});
}
if (!flag) {
printf("-1\n");
continue;
}
for (int i = 1; i <= n; i++) dis[i][0] = 0x7fffffffll * 100, dis[i][1] = 0x7fffffffll * 100;
for (int i = 1; i <= n; i++) book[i][0] = 0, book[i][1] = 0;
dis[1][0] = 0;
Q.push((node1){1, 0});
while (Q.size()) {
t = Q.top();
Q.pop();
tu = t.u;
tw = t.w;
if (book[tu][tw % 2]) continue;
book[tu][tw % 2] = 1;
for (int i = 0; i < V[tu].size(); i++) {
tw = t.w;
tv = V[tu][i].v;
if (tw < V[tu][i].w) {
tw += ((V[tu][i].w - tw) / 2) * 2;
if (tw < V[tu][i].w) tw += 2;
}
tw++;
if (dis[tv][tw % 2] > tw) {
dis[tv][tw % 2] = tw;
Q.push((node1){tv, tw, tw % 2});
}
}
}
ans = 0x7fffffffll * 100, minn = -0x7fffffffll * 100;
for (int i = 1; i <= n; i++) minn = max(minn, dis[i][0]);
ans = min(ans, minn);
minn = -0x7fffffffll * 100;
for (int i = 1; i <= n; i++) minn = max(minn, dis[i][1]);
ans = min(ans, minn);
if (ans != 0x7fffffffll * 100) printf("%lld\n", ans * o);
else printf("-1\n");
}
return 0;
}
::::