版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
治安点
题目
知识点:最短路,最短路的优化
贝克兰德有n个城镇,这些城镇之间有m条道路连接,每条道路有一个长度l。
zf在其中k个城镇设置了治安点。当一个城镇发生事件时,任意一个治安点都可以派人前往。但是为了节省资源,往往会选择距离最近的治安点。
那么请问,对于每一个城镇,最近的治安点距离为多少。
输入
第一行一个整数t表示数据组数(1≤t≤10)
每组数据第一行三个正整数n,m,k (1≤n≤103,n−1≤m≤n∗n/2,1≤k≤n)
第二行k个整数表示治安点所在的位置。
接下来m行,每行三个整数x,y,z,表示x,y之间有一条权值为z的边(无向边) (1≤x,y≤n,1≤z≤10000)
输出
每组数据一行,n个数
输入样例
1
4 7 2
1 4
1 2 7
1 3 2
1 4 6
2 1 1
2 4 1
3 2 1
3 4 3
输出样例
0 1 2 0
思路
第一眼看上去是跑k次最短路,优先队列优化的dijkstra算法跑一次复杂度为O(e×log(v))。这样写的话会tle。
那么怎么优化呢?事实上只需要添加k条边,从0到k个选择的点,权值为0,那么事实上只用跑一次即可。省去一维复杂度。
代码
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <iostream>
#include <map>
#include <random>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
const int ms = 1010;
const int mx = 1000;
int g[ms][ms], point[ms], d[ms], d1[ms];
vector<int> gr[ms];
int n, m, cnt, k;
priority_queue<pair<int, int>>q;
bool vis[ms];
void dij()
{
memset(d, 0x3f, sizeof(d));
memset(vis, false, sizeof(vis));
for (int i = 0; i < k; ++i)
{
q.push({ 0,point[i] }); d[point[i]] = 0;
}
while (!q.empty())
{
int x = q.top().second; q.pop();
if (vis[x]) continue;
vis[x] = true;
for (int i : gr[x])
{
int y = i, z = g[x][i];
if (d[y] > d[x] + z)
{
d[y] = d[x] + z;
q.push({ -d[y],y });
}
}
}
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
memset(g, 0x3f, sizeof(g));
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < k; ++i)
{
scanf("%d", &point[i]);
}
int x, y, z;
for (int i = 0; i < m; ++i)
{
scanf("%d%d%d", &x, &y, &z);
if (g[x][y] == 0x3f3f3f3f)
{
gr[x].push_back(y);
gr[y].push_back(x);
}
g[x][y] = min(g[x][y], z);
g[y][x] = min(g[y][x], z);
}
dij();
for (int i = 1; i <= n; ++i)
{
printf("%d ", d[i]);
gr[i].clear();
}
printf("\n");
}
return 0;
}