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