UVA 11374 Air Express

这道题其实就是这个意思:给你m条路,可以随便走;再给你K条路,这K条路一共只能走一次(可以不走),问从A到B最快要多久.

        这道题,其实是道水题,可以参考刘汝佳的蓝书P330。我们从A为起点,做一次单源最短路径,把点X离A的距离记为

dis[x][0],然后再以B为起点,做一次单源最短路径,把点X离B的距离记为dis[x][1]。我们设这K条路中任意一条路为x-y,长度为z且经过这条路,则A到B的路径只能是A-x-y-B或A-y-x-B。那么这个长度就是dis[x][0]+dis[y][1]+z或dis[x][1]+dis[y][0]+z,把最短的一个的x和y,最后再与直接从A到B(不走这K条路中的任意一条)对比一下,就算出了第二个答案和第三个答案了.统计路径,其实也很简单,具体参考代码


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,at,to;
int dis[1005][2],vis[1005];
struct node{
int to;
int dis;
       bool operator <(const node &rhs)const{
    return dis>rhs.dis;
}
}xs; 
struct Edge{
int from;
int to;
int len;
};
vector<Edge>edges;
vector<int>G[1005];
priority_queue<node>p;
int len;
void addedge(int x,int y,int z){
    edges.push_back((Edge){x,y,z});
G[x].push_back(len);
len++;
}
int last[1005][2];
void dijkstra(int k,int root){
int u;
    memset(vis,0,sizeof(vis));
    dis[root][k]=0;
    
    p.push((node){root,0});
    while(p.size()){
        xs=p.top();p.pop();
u=xs.to;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(dis[u][k]+e.len<dis[e.to][k]){
dis[e.to][k]=dis[u][k]+e.len;
last[e.to][k]=u;//记录它的上一个点
p.push((node){e.to,dis[e.to][k]});
}
}
}
}
int x,y,z,tmp,cases;
int where1,where2; 
stack<int>out; 
int main(){
while(scanf("%d%d%d%d",&n,&at,&to,&m)!=EOF){
if(cases)printf("\n");
cases++;
len=0; 
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);

memset(last,0,sizeof(last));
memset(dis,inf,sizeof(dis)); 
last[at][0]=last[to][1]=-1;
where1=where2=0;
int ans=inf;
dijkstra(0,at);
dijkstra(1,to);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
tmp=dis[x][0]+dis[y][1]+z;
if(tmp<ans){
ans=tmp;
where1=x;where2=y;
}
tmp=dis[y][0]+dis[x][1]+z;
if(tmp<ans){
ans=tmp;
where1=y;where2=x;
}
}
if(ans>dis[at][1]){
ans=dis[at][1];
where1=where2=0;

if(where1&&where2){
   x=where1;
   while(where1!=-1){
        out.push(where1);
        where1=last[where1][0];
   }
   while(out.size()){
        printf("%d ",out.top());
        out.pop();
   }
   printf("%d",where2);
   where2=last[where2][1];
   while(where2!=-1){
        printf(" %d",where2);
        where2=last[where2][1];
   }
   printf("\n%d\n",x);
     }
     else {
      x=last[at][1];
      printf("%d",at);      
      while(x!=-1){
      printf(" %d",x);
      x=last[x][1];

printf("\nTicket Not Used\n");
}
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)G[i].clear();
    edges.clear();
}
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值