道路和航路
农夫约翰正在针对一个新区域的牛奶配送合同进行研究。他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条标号为(1..P)的航路相连。
每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci。每一条公路,Ci的范围为0<=Ci<=10,000;由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000<=Ci<=10,000。
每一条公路都是双向的,正向和反向的花费是一样的,都是非负的。
每一条航路都根据输入的Ai和Bi进行从Ai->Bi的单向通行。实际上,如果现在有一条航路是从Ai到Bi的话,那么意味着肯定没有通行方案从Bi回到Ai。
农夫约翰想把他那优良的牛奶从配送中心送到各个城镇,当然希望代价越小越好,你可以帮助他嘛?配送中心位于城镇S中(1<=S<=T)。
输入的第一行包含四个用空格隔开的整数T,R,P,S。
接下来R行,描述公路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
接下来P行,描述航路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
输出T行,分别表示从城镇S到每个城市的最小花费,如果到不了的话输出NO PATH。
首先看到了负值,就想SPFA,但是一直没有用过。所以今天学习了一波
SPFA就是把起点入队,然后去松弛相连的边,如果可以松弛且相连没有入队,就入队。直到队列为空
注意 如果出队,就及时取消标记
如果一个点,入队次数 > n 就说明有负环
但是这道题需要SPFA优化
不用普通的队列,而是双端队列。如果松弛点的dis值小于队首就加入队首,否则加入队尾。
回忆一下前向星。
edge[i].to 表示第i条边的终点
edge[i].next 表示与第i条边同起点的边
head[i] 表示以i为起点的边的位置。
1 #include<bits/stdc++.h> 2 const int inf=0x3f3f3f3f; 3 using namespace std; 4 5 struct node{ 6 int to,next,w; 7 }edge[150010]; 8 int dis[25010],cnt,head[25010],vis[25010],c[25010]; 9 10 void add(int u,int v,int w) { 11 edge[cnt].to=v; 12 edge[cnt].next=head[u]; 13 edge[cnt].w=w; 14 head[u]=cnt++; 15 } 16 17 void spfa(int st,int n) { 18 for(int i=1;i<=n;i++) { 19 dis[i]=inf; 20 vis[i]=0; 21 c[i]=0; 22 } 23 dis[st]=0; 24 vis[st]=1; 25 deque<int> q; 26 q.push_front(st); 27 while(!q.empty()) { 28 int k=q.front(); 29 q.pop_front(); 30 vis[k]=0; 31 c[k]++; 32 if(c[k]>n) return; 33 for(int i=head[k];i!=-1;i=edge[i].next) { 34 if(dis[edge[i].to]>dis[k]+edge[i].w) { 35 dis[edge[i].to]=dis[k]+edge[i].w; 36 if(q.empty()) { 37 q.push_front(edge[i].to); 38 vis[edge[i].to]=1; 39 } else if(!vis[edge[i].to]){ 40 if(dis[q.front()]>dis[edge[i].to]) { 41 q.push_front(edge[i].to); 42 } else q.push_back(edge[i].to); 43 vis[edge[i].to]=1; 44 } 45 } 46 } 47 } 48 } 49 50 51 int main() { 52 int t,r,p,s; 53 while(~scanf("%d%d%d%d",&t,&r,&p,&s)) { 54 int a,b,c; 55 cnt=0; 56 memset(head,-1,sizeof(head)); 57 for(int i=0;i<r;i++) { 58 scanf("%d%d%d",&a,&b,&c); 59 add(a,b,c); 60 add(b,a,c); 61 } 62 for(int i=0;i<p;i++) { 63 scanf("%d%d%d",&a,&b,&c); 64 add(a,b,c); 65 } 66 spfa(s,t); 67 for(int i=1;i<=t;i++) { 68 if(dis[i]<inf) printf("%d\n",dis[i]); 69 else puts("NO PATH"); 70 } 71 } 72 return 0; 73 }