题目要求:
输入 n m
m行加入边,a b c 表示a到b的距离是c
输出一个整数表示从1到n的最短距离
第一道的范围到N=500,使用的是邻接矩阵.
思路:
第一步是找到当前的所有点中,找到没有延申到的最短的一个点是谁,设置为t
然后再更具这个点更新所有的点到1的最近的距离,最后循环所有的点,保证所有点都被访问到.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
int n,m;
bool st[N];
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
for(int j = 1 ; j <= n ; j ++)
if(!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
for(int j = 1; j <= n ; j ++)
dist[j] = min(dist[j], dist[t] + g[t][j]);
st[t] = true;
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g);
while (m -- ){
int a,b,c;
scanf("%d%d%d", &a,&b,&c);
g[a][b] = min(g[a][b],c);
}
cout<<dijkstra();
}
第二题与第一题一样区别在于范围变为 ,
需要使用堆优化,优化的部分是找到当前最近的一个点t的时候.从n方到nlogn.
同时使用的是邻接表版本的.
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010 ;
typedef pair<int, int> PII;
int h[N], e[N], w[N], ne[N], idx;
int dist[N];
bool st[N];
int n,m;
void add(int a,int b,int c){
e[idx] = b, w[idx] = c , ne[idx] = h[a] , h[a] = idx++;
}
int dijkstra() // 求1号点到n号点的最短路距离
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1});
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second, dis = t.first;
if(st[ver]) continue;
st[ver] = true;
//与ver直接相连的是这个链表上的也就是j,dist[j] = dist[ver] + 到j的距离也就是w[i];
for(int i = h[ver] ; i!=-1 ; i = ne[i]){
int j = e[i];
if(dist[j] > dis + w[i]){
// 更新最短的路,继续按这个路找下一个最短的路
dist[j] = dis + w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
add(a, b, c);
}
cout << dijkstra();
}
acwing 1488最短距离
题目要求(输入)
有N个村庄,村庄之间的道路有M条,连接与上类似,从a村到b村的距离为c
同时,有k个村庄有商店,编号和村庄的对应.
最后,有Q个询问,每次询问一个编号,这个编号的村庄最近的商店的距离是多少?
输出:
输出每个询问的结果.
思路:
可以想象每个商店是独立的个体,到达不同的村庄的距离就是和之前存的dist类似.这个时候有一个空结点0号结点,直接与这些点相连,到这些商店的距离都是0.
那么要求某个村庄最近的就是从0开始到这个村庄的最短路劲,因为本身要求的就是村庄到商店的最短路,这个时候加上了一段距离为0的点开始,对这个询问没有影响,对距离也没有影响,所以反过来,求0结点到这个村庄的最短路距离就是求村庄到这些商店的最短路.
做法主要是在dijkstra算法的基础之上,
从0号结点开始到损耗也是0,每次加入小卖部的时候,从0号结点开始加入,损耗也设置成为0.
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 100010 , M = N*3;
int n,m;
int h[N],e[M],ne[M],w[M],idx;
int dist[N];
bool st[N];
void add(int a,int b,int c){
e[idx] = b ,w[idx] = c , ne[idx] = h[a] , h[a] = idx++;
}
void dijkstra() // 求1号点到n号点的最短路距离
{
memset(dist, 0x3f, sizeof dist);
dist[0] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 0});
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b,c;
scanf("%d%d%d", &a, &b , &c);
add(a, b, c);
add(b, a, c);
}
scanf("%d", &m);
while(m--){
int x;
scanf("%d", &x);
add(0,x,0);
}
scanf("%d", &m);
dijkstra();
while (m -- ){
int x;
scanf("%d", &x);
printf("%d\n",dist[x]);
}
}