把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1543 最快路线

题面传送门
看到这道题,想到\(spfa\)
但这道题好像故意的,偏偏又路牌被拆的道路(在衢州的话负责那一段路的交警就该下台了),
所以我们不能只以\(d_i\)\(time\)的唯一标准。
想象一下:如果下一条路是没有路牌的,而这时过来一条路,\(time\)\(d_i\)大,但如果下一条路可以走得通怎么办?而且还走得比\(d_i\)快。这时候就进退两难,如果放过去,那\(spfa\)就废了。
如果不放过去,答案就废了。
想想\(flying\)经常说什么?\(dp\)状态表达不完整就再加一维状态!我们可以用\(dp\)的思路:以\(d_{i,j}\)表示以\(j\)速度开到\(i\)点所需最短时间。那么\(spfa\)还是照样松弛呗。
这道题要求我们输出经过点序,所以我们可以\(spfa\)的过程中当出现一个最优解时指回去。然后最后倒序输出。
代码实现:

#include<cstdio>
#include<queue>
using namespace std;
int n,m,k,x,y,z,h,zj[100039],head,now1[159][559],now2[159][559],tmp1,tmp2;
double dp[159][559],ans;
struct yyy{
    int a,b,c;
}f[159][159],cur;
struct fs{
    int mu,su;
}tmp;
queue<fs> q; 
int main(){
//  freopen("1.in","r",stdin);
    int i,j;
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=m;i++) scanf("%d%d%d%d",&x,&y,&z,&h),f[x][++f[x][0].a]=(yyy){y,z,h};
    q.push((fs){0,70});
    for(i=0;i<=500;i++) now1[0][i]=-1,now2[0][i]=-1;
    for(i=0;i<=150;i++){
        for(j=0;j<=550;j++) dp[i][j]=100000000;
    }
    dp[0][70]=0;
    while(!q.empty()){
        tmp=q.front();
        q.pop();
        for(i=1;i<=f[tmp.mu][0].a;i++){
            cur=f[tmp.mu][i];
            if(!cur.b){
                ans=dp[tmp.mu][tmp.su]+cur.c*1.0/tmp.su;
                if(ans<dp[cur.a][tmp.su]){
                    dp[cur.a][tmp.su]=ans;
                    now1[cur.a][tmp.su]=tmp.mu;
                    now2[cur.a][tmp.su]=tmp.su;
                    q.push((fs){cur.a,tmp.su});
                }
            }
            else{
                ans=dp[tmp.mu][tmp.su]+cur.c*1.0/cur.b;
                if(ans<dp[cur.a][cur.b]){
                    dp[cur.a][cur.b]=ans;
                    now1[cur.a][cur.b]=tmp.mu;
                    now2[cur.a][cur.b]=tmp.su;
                    q.push((fs){cur.a,cur.b});
                }
            }
        }
    }
    //printf("%d %d %d %d %d %d %d %d\n",now1[1][64],now2[1][64],now1[3][90],now2[3][90],now1[2][90],now2[2][90],now1[5][70],now2[5][70]);
    ans=1000000000;
    for(i=1;i<=550;i++){
        if(dp[k][i]>0) ans=min(ans,dp[k][i]);
    }
    for(i=1;i<=550;i++){
        if(dp[k][i]==ans){
            tmp1=now1[k][i];tmp2=now2[k][i];
            printf("0");
            while(tmp1){
                zj[++head]=tmp1;
                h=tmp1;x=tmp2;
                tmp1=now1[h][x];tmp2=now2[h][x];
            }
            for(j=head;j>=1;j--) printf(" %d",zj[j]);
            printf(" %d",k);
        }
    }
}

然而又要卡常......可能这道题有卡\(spfa\)的数据吧......
加寄存器,手写队列......又是卡过去的......\(966ms\)。本机都跑的飞快呀......
代码实现:

#include<cstdio>
#include<queue>
using namespace std;
int zj[1039],now1[159][559],now2[159][559];
double dp[159][559],ans;
struct yyy{
    int a,b,c;
}f[159][159];
struct fs{
    int mu,su;
}q[500039];
inline void read(int &x){
    x=0;char s=getchar();
    while(s<'0'||s>'9') s=getchar();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
//  freopen("fast.in","r",stdin);
//  freopen("fast.out","w",stdout);
    register int i,j,he=0,ta=0,cura,curb,tmpsu,tmpmu,curc,n,m,k,x,y,z,h,head=0,tmp1,tmp2;
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=m;i++) read(x),read(y),read(z),read(h),f[x][++f[x][0].a]=(yyy){y,z,h};
    q[++ta]=((fs){0,70});
    for(i=0;i<=500;i++) now1[0][i]=-1,now2[0][i]=-1;
    for(i=0;i<=n;i++){
        for(j=0;j<=500;j++) dp[i][j]=1000000000;
    }
    dp[0][70]=0;
    while(he!=ta){
        tmpsu=q[he+1].su;tmpmu=q[he+1].mu;
        he++;
        for(i=f[tmpmu][0].a;i>=1;i--){
            cura=f[tmpmu][i].a;curb=f[tmpmu][i].b;curc=f[tmpmu][i].c;
            if(!curb){
                ans=dp[tmpmu][tmpsu]+curc*1.0/tmpsu;
                if(ans<dp[cura][tmpsu]){
                    dp[cura][tmpsu]=ans;
                    now1[cura][tmpsu]=tmpmu;
                    now2[cura][tmpsu]=tmpsu;
                    q[++ta]=((fs){cura,tmpsu});
                }
            }
            else{
                ans=dp[tmpmu][tmpsu]+curc*1.0/curb;
                if(ans<dp[cura][curb]){
                    dp[cura][curb]=ans;
                    now1[cura][curb]=tmpmu;
                    now2[cura][curb]=tmpsu;
                    q[++ta]=((fs){cura,curb});
                }
            }
        }
    }
    //printf("%d %d %d %d %d %d %d %d\n",now1[1][64],now2[1][64],now1[3][90],now2[3][90],now1[2][90],now2[2][90],now1[5][70],now2[5][70]);
    ans=1000000000;
    for(i=1;i<=500;i++){
        if(dp[k][i]>0) ans=min(ans,dp[k][i]);
    }
    for(i=1;i<=500;i++){
        if(dp[k][i]==ans){
            tmp1=now1[k][i];tmp2=now2[k][i];
            while(tmp2!=-1&&tmp1!=-1){
                zj[++head]=tmp1;
                h=tmp1;
                tmp1=now1[h][tmp2];tmp2=now2[h][tmp2];
            }
            for(j=head;j>=1;j--) printf("%d ",zj[j]);
            printf("%d ",k);
        }
    }
}
posted @ 2020-03-24 11:52  275307894a  阅读(44)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end