ZOJ3088 Easter Holidays spfa 最长路 最短路 路径打印

题目链接:

3088





题意:一个滑雪胜地包含了n 个地点,m 个滑雪斜坡,k 架雪橇,其中2≤n≤1000、1≤m≤1000、1≤k≤1000。滑雪斜坡和雪橇总是从一个地点到另一个地点:滑雪斜坡是从高地点到低地点,而雪橇刚好相反(注意,雪橇不能下降)。Per 是一个滑雪初学者,他很害怕雪橇,尽管他想滑得尽可能快。现在,他发现他可以选择不同的雪橇和滑雪斜坡。他现在想这样安排他的滑雪行程:

1) 从一架雪橇的起点出发并最终回到起点。
2) 这个过程分为两个阶段:第一阶段,乘坐一架或多架雪橇上升;第二阶段,一直滑下来直到起点
3) 可能少地避免惊慌。这样,如果花在滑坡斜面上的时间与花在乘坐和等候雪橇的时间的比率越大就越好。


你能帮Per 找到一条惊慌最少的行程吗?




题解:

求两段路程的最大比率     即为求第一段的最长路径和第二段的最短路径(spfa算法)   且它们的起点和终点刚好相反     然后通过spfa(遍历所有起点 用dis数组记录到达所有其他点的最长路和最短路,并用path数组记录路径),最后枚举所有起点终点  输出比率的最大值即可。



代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxx 0x3f3f3f3f
using namespace std;
struct node{
    int to,w,pre;
} edge[2][1005];                  //一维0表示滑坡  1表示雪橇
int dis[2][1005][1005];           //dis   path的第二维表示所有起点
int path[2][1005][1005];                
int next[2][1005];
int vis[2][1005];
int loc[1005];                    //记录结果路径
int m,s1,s2;
void addedge(int x){
    int u,v,we,d;
    scanf("%d%d%d",&u,&v,&we);
    if(x==0)d=s1;
    else
        d=s2;
    edge[x][d].to=v;
    edge[x][d].w=we;
    edge[x][d].pre=next[x][u];
    next[x][u]=d;
    if(x==0)s1++;
    else
        s2++;
    return;
}
void spfa(int x,int start){
    queue<int>q;
    int head;
    dis[x][start][start]=0;
    q.push(start);
    while(!q.empty()){
        head=q.front();
        q.pop();
        vis[x][head]=0;
        for(int i=next[x][head]; i!=-1; i=edge[x][i].pre){
            int u=head,v=edge[x][i].to,we=edge[x][i].w;
            if(x==0){
                if(dis[x][start][v]<dis[x][start][u]+we){
                    dis[x][start][v]=dis[x][start][u]+we;
                    path[x][start][v]=u;
                    if(!vis[x][v]){
                        vis[x][v]=1;
                        q.push(v);
                    }
                }
            }
            else{
                if(dis[x][start][v]>dis[x][start][u]+we){
                    dis[x][start][v]=dis[x][start][u]+we;
                    path[x][start][v]=u;
                    if(!vis[x][v]){
                        vis[x][v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    return;
}
int main(){
    int t,n,k,i,j;
    scanf("%d",&t);
    while(t--){
        s1=s2=0;
        scanf("%d%d%d",&m,&n,&k);
        for(i=1; i<=m; i++){
            next[0][i]=next[1][i]=-1;
            for(j=i; j<=m; j++){
                path[0][i][j]=path[1][i][j]=path[0][j][i]=path[1][j][i]=-1;
                dis[0][i][j]=dis[0][j][i]=0;
                dis[1][j][i]=dis[1][i][j]=maxx;
            }
        }
        while(n--){
            addedge(0);
        }
        while(k--){
            addedge(1);
        }
        for(i=1; i<=m; i++){
            memset(vis,0,sizeof(vis));
            spfa(0,i);
            spfa(1,i);
        }
        double ans=0,q1,q2,q3;
        int start,endd,s3=0,pos;
        for(i=1; i<=m; i++)
            for(j=1; j<=m; j++){
                if(i==j||dis[0][i][j]==0||dis[1][j][i]==maxx)
                    continue;
                q1=dis[0][i][j],q2=dis[1][j][i];
                q3=q1/q2;
                if(q3>ans)
                    {start=i,endd=j,ans=q3;}
            }
        pos=endd;
        while(path[0][start][pos]!=-1){
            loc[s3++]=pos;
            pos=path[0][start][pos];
        }
        while(path[1][endd][pos]!=-1){
            loc[s3++]=pos;
            pos=path[1][endd][pos];
        }
        cout<<endd;
        for(i=s3-1;i>=0;i--)
            cout<<' '<<loc[i];
        printf("\n%.3lf\n",ans);
    }
    return 0;
}


  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值