. 给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
**算法的流程如下,
1:初始化d[1]=0,其余节点的d值为正无穷大
2:找出一个未被标记的、d[x]最小的节点x,然后标记节点x
3:扫描节点x的所有出边(x,y,z),如果d[y]>d[x]+z,就使用d[x]+z更新d[y]
这个算法只适用于所有的边长都非负的图,全局的最小值不可能被其他的节点更新,
**
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[3010][3010],d[3010],n,m,v[3010];
int dijkstra(){
memset(d,0x3f,sizeof d);//首先将距离初始化为最大值
memset(v,0,sizeof v);//将所有的节点都初始化为没有访问过
d[1]=0;
for(int i=1;i<=n;i++)
{
int x=0;
for(int j=1;j<n;j++)//这一层循环的目的是找到最小的值
{
if(!v[j]&&(x==0||d[j]<d[x]))
x=j;
}
v[x]=1;//找到最小的值后,最小的值确定好,不能在变
for(int y=1;y<=n;y++)//然后在判断从最小值出度的点的最小值
d[y]=min(d[y],d[x]+a[x][y]);
}
return d[n];
}
int main()
{
cin>>n>>m;
memset(a,0x3f,sizeof a);
for(int i=1;i<=n;i++)
a[i][i]=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x][y]=min(a[x][y],z);
}
int t=dijkstra();
if(t==0x3f3f3f3f)
cout<<"impossible";
else
printf("%d",d[n]);
return 0;
}
下面是用小根堆优化的代码
typedef pair<int, int> PII;
int n; // 点的数量
int h[N], w[N], e[N], ne[N], idx; // 邻接表存储所有边
int dist[N]; // 存储所有点到1号点的距离
bool st[N]; // 存储每个点的最短距离是否已确定
// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1}); // first存储距离,second存储节点编号
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] > distance + w[i])
{
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}