思路
求从 1 到 n 的最短路,需注意的是 图上所有边的边权会实时改变
如何改变:每次走过一条边之后,所有的 x 都会 执行一次操作:x = 1/(1-x),x 是 边权,所有的 x 指所有边
即 边权会随着走过的边的数目的改变而改变
所以该题 不再仅仅是最短路问题,而是变成了 最短路 + dp 问题
不妨令 dist[i][j]:表示 从 1 到 i 经过了 j 条边的最短路
所以 我们最终只需求 min( dist[n][0],dist[n][1],dist[n][2],...... ,dist[n][M] ) M 代表最多走过的边的数目
但是 因为边是双向边,所以理论上来讲 我们可走过无穷条边 ,开数组的话 需开成 dist[点的数目][正无穷]
显然 开不到那么大
所以我们需要作进一步的 优化:
观察 x = 1/(1-x) ,我们不难发现 执行三次该操作之后,x 会变回最初的 x
所以我们可以把 走过的边的数目 视为 0 、1 、2
0:表示走过了 3x 条边 ,x>=0
1:表示走过了 3x + 1条边,x>=0
2:表示走过了 3x + 2条边,x>=0
现在 dist[点的数目] [正无穷] 变成了 dist[点的数目] [3]
最终只需求 min( dist[n][0], dist[n][1], dist[n][2] ) 便可
注意:因为边权随着 走过边的数目的改变 而改变,所以我们需额外让 cnt 也入队
一些变量的解释:
cnt:走过边的数目 ,cnt取值 0、1、2
dist[i][j]:表示 从 1 到 i 经过了 '' j 条边 '' 的最短路 ,j 取值 0、1、2
st[i][j] = true 表示 从 1 到 i 经过了 '' j 条边 '' 的最短路已经确定 ,j 取值 0、1、2
综上,Code 如下 .
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 100010,M = 600010;
struct node{
double distance;
int id,cnt ;
bool operator < (const node &x) const{
return distance > x.distance;
}
};
int n,m;
bool st[N][4];
double w[M],dist[N][4];
int h[N],e[M],ne[M],idx;
double change_w(double x,int t){
t=t%3;
while(t--){
x = 1.0/(double)(1-x) ;
}
if(x<0) x=-x;
return x;
}
void add(int a,int b,double c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
double dijkstra(){
for(int i=1;i<=n;i++) dist[i][0]=dist[i][1]=dist[i][2]=1e10; // double型 不能用memset
dist[1][0]=0;
priority_queue<node> heap;
heap.push({0,1,0}) ;
while(heap.size()){
auto p=heap.top();
heap.pop();
int id=p.id,cnt=p.cnt;
double distance=p.distance;
if(st[id][cnt]) continue;
st[id][cnt]=true;
for(int i=h[id];i!=-1;i=ne[i]){
int j=e[i];
double d=change_w(w[i],cnt);
if(dist[j][(cnt+1)%3]>distance+d){
dist[j][(cnt+1)%3]=distance+d;
heap.push({dist[j][(cnt+1)%3],j,(cnt+1)%3}) ;
}
}
}
double res = 1e10;
for(int i=0;i<3;i++) res=min(res,dist[n][i]);
return res==1e10?-1:res;
}
int main(){
scanf("%d %d",&n,&m);
memset(h,-1,sizeof h);
while(m--){
int a,b,w;
scanf("%d %d %d",&a,&b,&w);
add(a,b,w),add(b,a,w);
}
double t=dijkstra();
if(t==-1) puts("-1");
else printf("%.3f\n",t);
return 0;
}
京公网安备 11010502036488号