P7271 Speed Limits
CommonDigger · · 题解
个人建议评绿或蓝。
类似分层图的思想。
题意
说得很清楚,一张有向图,边权由其长度
很容易发现,仅使用一维数组
所以,定义
在最短路算法中,对于每一条边:当它速度不明时,沿用速度 dis[to][v_old];否则尝试更新 dis[to][v]。另外,不建议使用 SPFA。
if(e[i].v==0){ // 这条边速度不明
// 沿用v__old,更新dis[to][v_old]
}else{
// 更新 dis[to][v]
}
由于最终要求输出路径,所以我们在更新最短路的同时记录这个点是由哪个点走过来的,因为要考虑速度,所以为它多开一维。
pair<int, int> pre[155][505] // 两个维度分别是 *点编号* 和 *速度*
pre[to][e[i].v]=make_pair(temp.id, temp.speed); // 由旧点更新到新点
怎么找路径呢? 我做的时候在这里卡了
首先,确定到达终点最优的状态,循环找出时间最短的速度,即找到使 dis[D][i] 最小的 i。然后再根据 pre 中的记录往后退,直到退回 0 号节点,途中再用数组记录路径(会光标倒退的可以直接输出)。
int path[505], dx=0, w=0;
for(int i=1;i<=500;i++){
if(dis[t][i]<dis[t][w]) w=i;
} // 找时间最小的状态,记录为 [t][w]
for(int walker=t, sp=w;walker!=0;){ // 于是从 pre[t][w]开始退
path[++dx]=walker;
pair<int, int>g=pre[walker][sp];
walker=g.first, sp=g.second;
}
cout << "0 ";
for(;dx>0;dx--){ // 倒序输出
cout << path[dx] << " ";
}
完整版
#include "iostream"
#include "cstring"
#include "queue"
using namespace std;
int head[155], idx, n, m, t;
pair<int, int> pre[155][505];
int temp1, temp2, temp3, temp4;
double dis[155][505];
struct edge{
int to, nxt, l, v;
}e[31250];
struct point{
double d;
int id, speed;
point(double d, int id, int speed){
this->d=d;
this->id=id;
this->speed=speed;
}
friend bool operator <(point p1, point p2){
return p1.d > p2.d;
}
};
void add_edge(int u, int v, int _v, int l){
e[++idx].to=v;
e[idx].l=l;
e[idx].v=_v;
e[idx].nxt=head[u];
head[u]=idx;
}
void dijkstra(){ // 差不多是模板了
memset(dis, 127, sizeof(dis));
priority_queue<point>q;
q.push(point(0, 0, 70)); // 点结构体:距离、编号、速度
while(!q.empty()){
point temp=q.top();
q.pop();
if(temp.d > dis[temp.id][temp.speed]) continue;
dis[temp.id][temp.speed]=temp.d;
for(int i=head[temp.id];i;i=e[i].nxt){
int to=e[i].to;
if(e[i].v==0){ // 速度不明,沿用旧速度
double nd=temp.d+e[i].l*1.0/temp.speed;
if(dis[to][temp.speed]>nd){
dis[to][temp.speed]=nd;
pre[to][temp.speed]=make_pair(temp.id, temp.speed);
q.push(point(nd, to, temp.speed));
}
}else{ // 自带速度,正常尝试更新
double nd=temp.d+e[i].l*1.0/e[i].v;
if(dis[to][e[i].v]>nd){
dis[to][e[i].v]=nd;
pre[to][e[i].v]=make_pair(temp.id, temp.speed);
q.push(point(nd, to, e[i].v));
}
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> t;
for(int i=1;i<=m;i++){
cin >> temp1 >> temp2 >> temp3 >> temp4;
add_edge(temp1, temp2, temp3, temp4);
}
dijkstra();
int path[505], dx=0, w=0;
for(int i=1;i<=500;i++){
if(dis[t][i]<dis[t][w]) w=i;
}
for(int walker=t, sp=w;walker!=0;){
path[++dx]=walker;
pair<int, int>g=pre[walker][sp];
walker=g.first, sp=g.second;
}
cout << "0 ";
for(;dx>0;dx--){
cout << path[dx] << " ";
}
}
21 年发的题目了,24 年 10 月开始写这个题解的时候,提交仅 36,通过5。这道题是真的没人看啊