CF938D Buy a Ticket

 

 

 

思路分析:从数据范围我们可以看出,从每个点跑一遍最短路肯定是不行的,于是我们想,这道题的行走方式可以简单优化一下,我们在建图时建上双倍边权,就不用再考虑来回了,之后再来考虑点权的问题,我们在从一个点出发,经过几个点,最终到达目的地,只用到了一次点权,即终点的点权。于是我们是不是可以倒着走呢?从终点向起点前进,路程都是一样的。很久之前我们曾做过一道“挖水井”的题目。那道题用到了虚点的思路,当然我们这道题也能用,我们建一个虚点,它和其他节点的边权就是当地门票钱。之后从虚点出发跑一下最短路,我们就可以解决这道问题了。(Spfa会超时!!!会超时!!!会超时!!!)。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 const int N=1e6+10;
 7 typedef long long ll;
 8 struct Node{
 9     int next,to;
10     ll dis;
11 }edge[N];
12 int Head[N],tot;
13 int n,m;
14 void Add(int x,int y,ll z){
15     edge[++tot].to=y;
16     edge[tot].next=Head[x];
17     edge[tot].dis=z;
18     Head[x]=tot;
19 }
20 struct Edge{
21     ll dis;
22     int num;
23     Edge(int x,ll y){
24         num=x;dis=y;
25     }
26     bool operator < (const Edge& a)const{
27         return a.dis<dis;
28     }
29 };
30 ll dis[N];
31 int vis[N];
32 priority_queue<Edge>q;
33 void dijkstra(int x){
34     for(int i=1;i<=n+1;++i)
35         dis[i]=2e13;
36     memset(vis,0,sizeof(vis));
37     q.push(Edge(x,0));
38     dis[x]=0;
39     while(!q.empty()){
40         Edge top=q.top();q.pop();
41         if(vis[top.num]) continue;
42         vis[top.num]=1;
43         int u=top.num;
44         for(int i=Head[u];i;i=edge[i].next){
45             int v=edge[i].to;
46             if(dis[v]>dis[u]+edge[i].dis){
47                 dis[v]=dis[u]+edge[i].dis;
48                 q.push(Edge(v,dis[v]));
49             }
50         }
51     }
52 }
53 ll cost[N];
54 int main(){
55     scanf("%d%d",&n,&m);
56     for(int i=1;i<=m;++i){
57         int x,y;
58         ll z;
59         scanf("%d%d%lld",&x,&y,&z);
60         Add(x,y,2*z);Add(y,x,2*z);
61     }
62     for(int i=1;i<=n;++i){
63         scanf("%lld",&cost[i]);
64         Add(n+1,i,cost[i]);
65     }
66     dijkstra(n+1);
67     for(int i=1;i<=n;++i)
68         printf("%lld ",dis[i]);
69     puts("");
70     return 0;
71 }
View Code

 

posted @ 2020-05-27 23:29  19502-李嘉豪  阅读(217)  评论(0编辑  收藏  举报