Dijkstra
该算法主要用于解决途中没有负边的单源点最短路问题
复杂度 O((n+m)logn)
每次从可以到达的顶点中,选取路径最短的一条路径,并过呢更新其可到达的点距离源点的最短路径长度。
比较dis[y] > dis[x] + w的大小这一过程被称为松弛
若dis[y] > dis[x] + w,则松弛成功
更新dis[y]的大小
将y加入最小堆
每一条边只会被堆弹出一次
一旦某个点被最小堆谭舒,则不会被松弛,dis的值为最短路
#include<bis/stdc++.h>
#define N 200003
#define pa pair<int,int>
#define inf 1e9
using namespace std;
int dis[N],vis[N],n,m,s;
int tot,point[N],w[N],v[N],nxt[N];
void add(int x,int y,int z)
{
tot++;
nxt[tot] = point[x];
point[x] = tot;
w[tot] = z;
v[tot] = y;
}
void dijkstra(int s )
{
priority_queue<pa,vector<pa>,greater<pa>> q;
//q中放的是已知路径长度的顶点
//每次取出路径最短的点
for(int i = 1;i<= n;i++)
dis[i] == inf,vis[i] = 0;
dis[s] = 0;
q.push(make_pair(0,s));
while(!q.empty())
{
int x = q.top.second();
q.pop();
if(vis[x]) continue;
vis[x]= 1;//以为一个点可能被入堆多次,减少复杂度!
for(int i = point[x];i;i=nxt[i])
if(dis[v[i]] > dis[x] + w[i])
{
//松弛路径最短的点所邻接点的路径
dis[v[i]] = dis[x] + w[i];
q.push(mak_pair(dis[v[i]],v[i]));
}
}
}
应用问题
单向路径车站往返
有n个车站,其中1号车站为始发站,现有n-1个人,你需要安排他们分别去往除始发站以外的n-1个车站,然后返回始发站。交通系统的所有路径均为单向路径,连接两个不同的车站,每经过一条路径需要交纳一定的费用,你能求出总花费的最低金额嘛
输入格式
第一行一个整数T,表示测试用例的个数。
对于每个测试用例,输入格式如下
第一行两个整数n,m,分别表示车站的数量和车站之间的单向路径数。
接下来m行,每行三个数s,e,c,表示存在从s到e的单向路径,花费为c
输入样例
2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50
输出样例
46
210
问题分析:
从始发车站,跑单源点最短路径,可以的到始发点到任意车站的最短路。但是由于路径是单向的,从各个车站回来的时候,如果也从每一个车站跑一个单源点最短路,复杂度太大。如果用floyd O(n^3)也是难以接受的。
我们考虑,如果有一条最短路从车站a反回始发站0,那么将所有路径取反,从始发车站0,到车站a的最短路应该就是刚才那一条路径的反向。
我们就可以存两个图,同时存正向图和反向图。两次最短路就可以求到了。
#include<bits/stdc++.h>
#define N 1000010
#define pa pair<int,int>
#define inf 1e9
using namespace std;
int vis1[N],vis2[N],n,m;
int dis1[N],dis2[N];
int tot,point1[N],w1[N],v1[N],nxt1[N];
int point2[N],w2[N],v2[N],nxt2[N];
void init()
{
tot = 0;
memset(point1,0,sizeof(point1));
memset(point2,0,sizeof(point2));
memset(dis1,0,sizeof(dis1));
memset(dis2,0,sizeof(dis2));
}
void add(int x,int y ,int z)
{
tot++;
nxt1[tot] = point1[x];
point1[x] = tot;
v1[tot] = y;
w1[tot] = z;
nxt2[tot] = point2[y];
point2[y] = tot;
v2[tot] = x;
w2[tot] = z;
}
void dijkstra(int n,int * point,int * dis,int * vis,int * w,int * v,int* nxt)
{
int s = 1;
priority_queue<pa, vector<pa>,greater<pa> > q;
for(int i=1;i<=n;i++)
{
dis[i]=inf;
vis[i]=0;
}
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty())
{
int x = q.top().second;
q.pop();
if(vis[x]) continue;
vis[x] =1;
for(int i=point[x];i;i=nxt[i])
if(dis[v[i]] > dis[x] + w[i])
{
dis[v[i]] = dis[x]+w[i];
q.push(make_pair(dis[v[i]],v[i]));
}
}
}
int main()
{
// freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T;
cin>>T;
for(int t=0;t <T;t++)
{
cin>>n>>m;
init();
for(int i =0 ;i < m;i++ )
{
int s,e,c;
cin>>s>>e>>c;
add(s,e,c);
}
dijkstra(n,point1,dis1,vis1,w1,v1,nxt1);
dijkstra(n,point2,dis2,vis2,w2,v2,nxt2);
int totalC = 0;
for(int i=1;i<=n;i++)
{
totalC = totalC + dis1[i] + dis2[i];
}
cout<<totalC <<endl;
}
return 0;
}