P5304 [GXOI/GZOI2019]旅行者 题解
这题有 做法。
考虑类似求次短路的方式,对于每个点 求出能到它最近的关键点 ,它能到最近的关键点 ,即 ,这一步正反图多源最短路跑两遍即可。
然后枚举每一条边 ,如果 ,那么说明 经过这条边并且这条路径一定是最短路,更新答案即可。
可以证明,答案一定会被包含并且非法状态不会被包含。
Code:
/*
========= Plozia =========
Author:Plozia
Problem:P5304 [GXOI/GZOI2019]旅行者
Date:2022/10/2
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
using std::priority_queue;
const int MAXN = 1e5 + 5, MAXM = 5e5 + 5;
int n, m, k, Head[MAXN], cntEdge, Point[MAXN], Color[2][MAXN];
LL dis[2][MAXN];
bool book[MAXN];
struct node { int To; LL val; int Next; } Edge[MAXM];
struct EDGE { int x, y, z; } e[MAXM];
struct pri { int x; LL dis; bool operator <(const pri &fir)const { return (dis > fir.dis); } } ;
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
return sum * fh;
}
LL Min(LL fir, LL sec) { return (fir < sec) ? fir : sec; }
void add(int x, int y, int z) { ++cntEdge; Edge[cntEdge] = (node){y, z, Head[x]}; Head[x] = cntEdge; }
void Dijkstra(int opt)
{
priority_queue <pri> q;
for (int i = 1; i <= n; ++i) book[i] = 0, dis[opt][i] = 0x7f7f7f7f7f7f7f7f, Color[opt][i] = 0;
for (int i = 1; i <= k; ++i) dis[opt][Point[i]] = 0, Color[opt][Point[i]] = Point[i], q.push((pri){Point[i], 0});
while (!q.empty())
{
int x = q.top().x; q.pop(); if (book[x]) continue ; book[x] = 1;
for (int i = Head[x]; i; i = Edge[i].Next)
{
int u = Edge[i].To; if (book[u]) continue ;
if (dis[opt][u] > dis[opt][x] + Edge[i].val)
{
dis[opt][u] = dis[opt][x] + Edge[i].val;
Color[opt][u] = Color[opt][x]; q.push((pri){u, dis[opt][u]});
}
}
}
}
void Solve()
{
n = Read(), m = Read(), k = Read();
for (int i = 1; i <= m; ++i) { e[i].x = Read(), e[i].y = Read(), e[i].z = Read(); add(e[i].x, e[i].y, e[i].z); }
for (int i = 1; i <= k; ++i) Point[i] = Read();
Dijkstra(0); cntEdge = 0; for (int i = 1; i <= n; ++i) Head[i] = 0;
for (int i = 1; i <= m; ++i) add(e[i].y, e[i].x, e[i].z);
Dijkstra(1); LL ans = 0x7f7f7f7f7f7f7f7f;
for (int i = 1; i <= m; ++i)
{
if (Color[0][e[i].x] != 0 && Color[1][e[i].y] != 0 && Color[0][e[i].x] != Color[1][e[i].y]) ans = Min(ans, dis[0][e[i].x] + dis[1][e[i].y] + e[i].z);
}
printf("%lld\n", ans); cntEdge = 0; for (int i = 1; i <= n; ++i) Head[i] = 0;
}
int main()
{
int t = Read(); while (t--) Solve(); return 0;
}
标签:
基础图论/树算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具