#include<bits/stdc++.h>
using namespace std;
int n,m,d;
struct node
{
int d,v,l;
};
struct no1
{
int v;
double d;
bool operator < (const no1 &y)const
{
return d > y.d;
}
};
vector <node> e[150];
double nvdis[150][150];//没有速度的最短路
double INF;
vector <int> nvpass[150][150];//没有速度最短路的途径地点
int vis[150];
double dis[150];
struct no2
{
int v;
int mode;//表示当前点是否是通过无速度边转移的,是为1,否为2
};
vector <no2> pas[150];
void nvdij(int x)
{
memset(vis,0,sizeof(vis));
priority_queue <no1> q;
nvdis[x][x] = 0;
q.push(no1{x,0});
while(!q.empty())
{
no1 v = q.top();
q.pop();
if(vis[v.v] == 1)continue;
vis[v.v] = 1;
int maxx = e[v.v].size();
for (int i = 0; i < maxx; i++)
{
int u = e[v.v][i].d;
if(e[v.v][i].v == 0 && vis[u] == 0 && nvdis[x][u] > nvdis[x][v.v] + e[v.v][i].l)
{
nvdis[x][u] = nvdis[x][v.v] + e[v.v][i].l;
nvpass[x][u] = nvpass[x][v.v];
nvpass[x][u].push_back(u);//只记录终点,不记录起点
q.push(no1{u,nvdis[x][u]});
}
}
}
}
void dij(int x)
{
memset(vis,0,sizeof(vis));
priority_queue<no1> q;
q.push(no1{x,0});
dis[x] = 0;
for (int i = 1; i < n; i++)
{
if(nvdis[0][i] != INF)
{
dis[i] = (1. * nvdis[0][i] / 70);
pas[i].push_back(no2{i,1});//只记录终点,不记录起点
q.push(no1{i,dis[i]});
}
}
while(!q.empty())
{
no1 v = q.top();
q.pop();
if(v.v == d)break;
if(vis[v.v] == 1)continue;
vis[v.v] = 1;
int maxx = e[v.v].size();
for (int i = 0; i < maxx; i++)
{
int u = e[v.v][i].d;
int l = e[v.v][i].l;
int vs = e[v.v][i].v;
if(vs && vis[u] == 0 && dis[u] > dis[v.v] + (1. * l / vs))
{
dis[u] = dis[v.v] + (1. * l / vs);
pas[u] = pas[v.v];
pas[u].push_back(no2{u,2});
q.push(no1{u,dis[u]});
}
if(vs)for (int i = 0; i < n; i++)
{
if(i != u && vis[i] == 0 && nvdis[u][i] != INF && dis[i] > dis[v.v] +(1. * l / vs) + (1. * nvdis[u][i] / vs))
{
dis[i] = dis[v.v] +(1. * l / vs) + (1. * nvdis[u][i] / vs);
pas[i] = pas[v.v];
pas[i].push_back(no2{u,2});//只记录终点,不记录起点
pas[i].push_back(no2{i,1});
q.push(no1{i,dis[i]});
}
}
}
}
}
int main()
{
cin >> n >> m >> d;
int a,b,v,l;
for (int i = 1; i <= m; i++)
{
cin >> a >> b >> v >> l;
e[a].push_back(node{b,v,l});
}
for (int i = 0 ;i < 150; i++)
{
for (int j = 0; j < 150; j++)
{
nvdis[i][j] = 1. * 1e9;
}
dis[i] = 1. * 1e9;
}
INF = dis[0];
for (int i = 0; i < n; i++)
{
nvdij(i);
}
dij(0);
int maxx = pas[d].size();
cout << 0 << " ";
for (int i = 0; i < maxx; i++)
{
no2 t = pas[d][i];
if(t.mode == 1)//无速度路转移
{
int prev = (i ? pas[d][i - 1].v : 0);
int max2 = nvpass[ prev ][t.v].size();
for (int j = 0; j < max2; j++)
{
cout << nvpass[prev][t.v][j] << " ";
//cout << endl << prev << endl;
}
}
else
{
cout << pas[d][i].v << " ";
}
}
return 0;
}
本题有两种做法:
1.分层图,(距离,速度)的二元点对
2. 合并速度为0的点
我是用的2做法,主要讲讲2
合并的想法,整的只是突发奇想,我也不知道怎么来的,但一开始想到的算法是错误的。。。看了题解中和我基础思路一样的才意识到。。。
2做法涉及到的dij贪心特点,也是阻碍,就是本题中点的状态对未来会有影响,那个点的状态指的就是到达当前点的速度
如何化解:
1.先对于只有速度为0的边的图跑一个路程的全源最短路
2.跑一边正经的dij,要加上每一次走一条速度不为0的边的时候,枚举走到的点(当作一个中转站)到其他所有点,只走速度为0的边,此时速度有了,那便可以更新,最重要的是,更新到的点v,之后与v相连的所有速度不为0的点,没有影响,速度为0的点,会在当前这一步进行计算,不依赖于v点,所以符合dij的贪心法则
注意:
1.善用vector,整的很方便!!!
2.(1. * int) 可以表示double
3.不能用memset(0x3f)初始化double或float