G - Repairing a Road
题意:给定n个点,m条边,每条边有一个a和v,求从1到n的最少时间
结果每条边的时间为v,并且可以修理一条边(仅可选择一次),使得经过该边的时间变为va−t,t为当前时间
解法:先用floyd计算每两个点之间的最小值
然后枚举每条边,将经过该边的时间变为va−t,与最小值进行比较。
(经过修理的边时可以等待一段时间,使得va−t+t最小)
#include<bits/stdc++.h> using namespace std; int n,m; struct Edge{ int x,y; double a,v; }e[505]; double dis[105][105],ans; void floyd(){ for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } void update(){ for(int i=0;i<m;i++){ int x=e[i].x,y=e[i].y; double a=e[i].a,v=e[i].v; double cnt=1/log(a)+log(v*log(a))/log(a); if(log(v*log(a))/log(a)>=dis[1][x]){ ans=min(ans,cnt+dis[y][n]); }else{ ans=min(ans,dis[1][x]+min(v/pow(a,dis[1][x]),dis[x][y])+dis[y][n]); } if(log(v*log(a))/log(a)>=dis[1][y]){ ans=min(ans,cnt+dis[x][n]); }else{ ans=min(ans,dis[1][y]+min(v/pow(a,dis[1][y]),dis[y][x])+dis[x][n]); } } } int main(){ while(cin>>n>>m){ if(!n&&!m) break; memset(e,0,sizeof(e)); memset(dis,0,sizeof(dis)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i==j) dis[i][j]=0; else dis[i][j]=INT_MAX; for(int i=0;i<m;i++){ cin>>e[i].x>>e[i].y>>e[i].v>>e[i].a; dis[e[i].x][e[i].y]=e[i].v; dis[e[i].y][e[i].x]=e[i].v; } floyd(); ans=dis[1][n]; /*for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++) cout<<dis[i][j]<<' '; cout<<endl; }*/ update(); printf("%.3f ",ans); } }