1. 程式人生 > >道路和航路

道路和航路

head col color 接下來 ack turn 次數 ont next

農夫約翰正在針對一個新區域的牛奶配送合同進行研究。他打算分發牛奶到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 }

道路和航路