G - Repairing a Road

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\n",ans);
    }
}

 

posted @ 2020-09-22 16:23  xuanzo  阅读(153)  评论(0编辑  收藏  举报