道路和航线(最短路SPFA优化算法)

 道路和航线

时间限制: 1 Sec  内存限制: 128 MB

题目描述

Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T。这些城镇之间通过R条道路 (1 <= R <= 50,000,编号为1到R) 和P条航线 (1 <= P <= 50,000,编号为1到P) 连接。每条道路i或者航线i连接城镇Ai (1 <= Ai <= T)到Bi (1 <= Bi <= T),花费为Ci。对于道路,0 <= Ci <= 10,000;然而航线的花费很神奇,花费Ci可能是负数(-10,000 <= Ci <= 10,000)。道路是双向的,可以从Ai到Bi,也可以从Bi到Ai,花费都是Ci。然而航线与之不同,只可以从Ai到Bi。事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台 了一些政策保证:如果有一条航线可以从Ai到Bi,那么保证不可能通过一些道路和航线从Bi回到Ai。由于FJ的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇S(1 <= S <= T) 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。

输入

* 第1行:四个空格隔开的整数: T, R, P, and S * 第2到R+1行:三个空格隔开的整数(表示一条道路):Ai, Bi 和 Ci * 第R+2到R+P+1行:三个空格隔开的整数(表示一条航线):Ai, Bi 和 Ci

输出

* 第1到T行:从S到达城镇i的最小花费,如果不存在输出"NO PATH"。
 

样例输入 Copy

6 3 3 4
1 2 5
3 4 5
5 6 10
3 5 -100
4 6 -100
1 3 -10

样例输出 Copy

NO PATH
NO PATH
5
0
-95
-100

提示

一共六个城镇。在1-2,3-4,5-6之间有道路,花费分别是5,5,10。同时有三条航线:3->5,
4->6和1->3,花费分别是-100,-100,-10。FJ的中心城镇在城镇4。
FJ的奶牛从4号城镇开始,可以通过道路到达3号城镇。然后他们会通过航线达到5和6号城镇。
但是不可能到达1和2号城镇。

题解:最短路的题 ,直接跑最短路SPFA 的话,会被卡 ,加O3一样会被卡 ,所以 就用SPFA的优化 ,优化有以下几点:
1.将SPFA中的queue队列换成deque双端队列
2. 当队列非空时,判断当前dis[v]与和队首比较 然后将数值小的放在队首,方便快速更新
  if (!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v);
  else q.push_back(v);
3.复习一下SPFA ,加边    初始化head【】=-1   
                               跑SPFA  声明dis【】到原点的距离   vis【】是否在队列中  队列  
                               初始化 n个点 的dis【】=INT_MAX  memset vis 为 0
                               原点加入队列  dis=0 标记vis=1;
                               跑循环, 从队列取出一个数,遍历点所到达所有边 ,用队列中已经被更新的点,当 dis[v]>dis[now]+edg[i].w 更新其他点,然后加队列标记
 
 1 #pragma GCC optimize(3,"Ofast","inline")
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int N=500000;
 5 int n,r,p,s;
 6 struct ss
 7 {
 8     int u,v,w,next;
 9 }edg[N];
10 int sumedg,head[N];
11 void addedg(int u,int v,int w)
12 {
13     edg[sumedg]=(ss){u,v,w,head[u]};
14     head[u]=sumedg++;
15 }
16 int dis[N];
17 bool vis[N];
18 void spfa()
19 {
20     deque<int>q;
21     for(int i=0;i<n+10;i++) dis[i]=INT_MAX;
22     memset(vis,0,sizeof(vis));
23     q.push_back(s);
24     vis[s]=1;
25     dis[s]=0;
26     long long sum1=0,sum2=1;
27  
28     while(!q.empty())
29     {
30         int now=q.front();q.pop_front();
31  
32         sum2--;
33         sum1-=dis[now];
34  
35         while(sum2&&sum2*dis[now]>sum1)
36         {
37             q.push_back(now);
38             sum1+=dis[now];
39             now=q.front();
40             q.pop_front();
41             sum1-=dis[now];
42         }
43  
44         vis[now]=0;
45         for(int i=head[now];i!=-1;i=edg[i].next)
46         {
47             int v=edg[i].v;
48             if(dis[v]>dis[now]+edg[i].w)
49             {
50                 dis[v]=dis[now]+edg[i].w;
51                 if(!vis[v])
52                 {
53                     vis[v]=1;
54                     if(!q.empty()&&dis[v]<dis[q.front()]) q.push_front(v);
55                     else q.push_back(v);
56  
57                     sum1+=dis[v];
58                     sum2++;
59                 }
60             }
61         }
62     }
63 }
64 int main()
65 {
66     scanf("%d%d%d%d",&n,&r,&p,&s);
67     for(int i=0;i<=n;i++) head[i]=-1;
68     for(int i=0;i<r;i++)
69     {
70         int u,v,w;
71         scanf("%d%d%d",&u,&v,&w);
72         addedg(u,v,w);
73         addedg(v,u,w);
74     }
75     for(int i=0;i<p;i++)
76     {
77         int u,v,w;
78         scanf("%d%d%d",&u,&v,&w);
79         addedg(u,v,w);
80     }
81     spfa();
82     for(int i=1;i<=n;i++)
83     {
84         if(dis[i]!=INT_MAX) printf("%d\n",dis[i]);
85         else printf("NO PATH\n");
86     }
87     return 0;
88 }

猜你喜欢

转载自www.cnblogs.com/sylvia1111/p/11871220.html