[UVA 11374] Airport Express

图片加载可能有点慢,请跳过题面先看题解,谢谢
1196604-20171029172402664-1873710328.png
1196604-20171029172151508-1093228711.png
1196604-20171029172155367-2113505237.png

\(UVA\)这个\(pdf\)做得真的蠢。。。那张图片把字都盖没了。。。
$
$
又是一道图论水题,快联赛了我还是只会切水题,果然还是太菜了
(话说今天忌装弱。。。)
1196604-20171029172819039-421086435.png
$
$
不过说实话这道题是真的水,做法也很简单
跑两遍单源最短路,分别求出从起点和从终点出发到每个点最短路
然后直接枚举商业车,对于一条商业车道 \(i\) ,用\(dis1[x]+w[i]+dis2[v]\)\(dis2[x]+w[i]+dis1[v]\)来更新答案即可
然后就是扣点,对于最短路上的点,一定满足前一个点\(x\)\(dis\)加上边权等于后一个点\(v\)\(dis\),就这样\(dfs\)或者\(bfs\)求就行
$
$

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define N (540)
#define M (2010)
using namespace std;
void File(){freopen(".in","r",stdin);freopen(".out","w",stdout);}

int t,n,S,E,m,K;
int Q[N],k1,k2,sh,cnt;
struct Edge{int u,v,w;}e[M];
int num,head[N],nxt[M],to[M],w[M];
void add(int u,int v,int d){
  nxt[++num]=head[u];to[num]=v;w[num]=d;head[u]=num;
  nxt[++num]=head[v];to[num]=u;w[num]=d;head[v]=num;
}

void init(){ if(t) puts("");t++;
  num=k1=k2=cnt=0;
  memset(head,0,sizeof(head));
  scanf("%d",&m);
  for(int i=1;i<=m;i++){
    int u,v,d;
    scanf("%d%d%d",&u,&v,&d);
    add(u,v,d);
  }
  scanf("%d",&K);
  for(int i=1;i<=K;i++)
    scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}

bool vis[N];
int dis1[N],dis2[N];
struct node{int x,dis;
  bool operator<(const node& a)const{ return dis>a.dis; }
};
priority_queue<node>que;

void Dij(int s,int* dis){
  memset(vis,0,sizeof(vis));
  que.push((node){s,0}); dis[s]=0;
  while(!que.empty()){
    node Q=que.top(); que.pop();
    int x=Q.x,d=Q.dis;
    if(vis[x]) continue;
    for(int i=head[x];i;i=nxt[i]){
      int v=to[i];
      if(dis[v]>dis[x]+w[i]){
    dis[v]=dis[x]+w[i];
    que.push((node){v,dis[v]});
      }
    }
    vis[x]=1;
  }
}

void dfs(int x,int* dis){
  Q[++cnt]=x; if(!dis[x]) return ;
  for(int i=head[x];i;i=nxt[i]){
    int v=to[i];
    if(dis[x]==dis[v]+w[i])
      dfs(v,dis);
  }
}

void work(){
  memset(dis1,127/3,sizeof(dis1));
  memset(dis2,127/3,sizeof(dis2));
  Dij(S,dis1); Dij(E,dis2); sh=dis1[E];
  for(int i=1;i<=K;i++){
    int u=e[i].u,v=e[i].v,d=e[i].w;
    int d1=dis1[u]+d+dis2[v];
    int d2=dis2[u]+d+dis1[v];
    if(d1<sh) sh=d1,k1=u,k2=v;
    if(d2<sh) sh=d2,k1=v,k2=u;
  }
  if(k1){ 
    dfs(k1,dis1),K=cnt,dfs(k2,dis2);
    for(int i=K;i;i--) printf("%d ",Q[i]);
    for(int i=K+1;i<cnt;i++) printf("%d ",Q[i]);
    printf("%d\n",Q[cnt]);
    printf("%d\n",k1);
  }
  else{ 
    dfs(S,dis2);
    for(int i=1;i<cnt;i++) printf("%d ",Q[i]);
    printf("%d\n",Q[cnt]);
    puts("Ticket Not Used");
  }
  printf("%d\n",sh);
}

int main(){ while(scanf("%d%d%d",&n,&S,&E)!=EOF){ init(); work(); } return 0; }

转载于:https://www.cnblogs.com/Hero-of-someone/p/7750520.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值