1. 程式人生 > >2200: [Usaco2011 Jan]道路和航線 (拓撲排序+dijstra)

2200: [Usaco2011 Jan]道路和航線 (拓撲排序+dijstra)

雙向 event 部分 連通 -a spfa eap dijstra 同時

Description

Farmer John正在一個新的銷售區域對他的牛奶銷售方案進行調查。他想把牛奶送到T個城鎮 (1 <= T <= 25,000),編號為1T。這些城鎮之間通過R條道路 (1 <= R <= 50,000,編號為1到R) 和P條航線 (1 <= P <= 50,000,編號為1到P) 連接。每條道路i或者航線i連接城鎮A_i (1 <= A_i <= T)到B_i (1 <= B_i <= T),花費為C_i。對於道路,0 <= C_i <= 10,000;然而航線的花費很神奇,花費C_i可能是負數(-10,000 <= C_i <= 10,000)。道路是雙向的,可以從A_i到B_i,也可以從B_i到A_i,花費都是C_i。然而航線與之不同,只可以從A_i到B_i。事實上,由於最近恐怖主義太囂張,為了社會和諧,出臺 了一些政策保證:如果有一條航線可以從A_i到B_i,那麽保證不可能通過一些道路和航線從B_i回到A_i。由於FJ的奶牛世界公認十分給力,他需要運送奶牛到每一個城鎮。他想找到從發送中心城鎮S(1 <= S <= T) 把奶牛送到每個城鎮的最便宜的方案,或者知道這是不可能的。

Input

* 第1行:四個空格隔開的整數: T, R, P, and S * 第2到R+1行:三個空格隔開的整數(表示一條道路):A_i, B_i 和 C_i * 第R+2到R+P+1行:三個空格隔開的整數(表示一條航線):A_i, B_i 和 C_i

Output

* 第1到T行:從S到達城鎮i的最小花費,如果不存在輸出"NO PATH"。

Sample Input



6 3 3 4

1 2 5

3 4 5

5 6 10

3 5 -100

4 6 -100

1 3 -10



樣例輸入解釋:



一共六個城鎮。在1-2,3-4,5-6之間有道路,花費分別是5,5,10。同時有三條航線:3->5,

4->6和1->3,花費分別是-100,-100,-10。FJ的中心城鎮在城鎮4。





Sample Output



NO PATH

NO PATH

5

0

-95

-100



樣例輸出解釋:



FJ的奶牛從4號城鎮開始,可以通過道路到達3號城鎮。然後他們會通過航線達到5和6號城鎮。

但是不可能到達1和2號城鎮。

思路: 因為有負權邊,所以不能使用dijstra,但是這個數據量使用spfa會t,所以我們考錄heap+dijstra。 如何解決負權邊呢??註意題目:如果有一條航線可以從A_i到B_i,那麽保證不可能通過一些道路和航線從B_i回到A_i。 這就說明,單向邊一定不會形成環。 所以一個聯通塊中,不可能有一個起點和終點都在這個強聯通塊的單向邊,然且對於兩個強連通塊,只能出項從一個塊指向另一個塊的單向邊,若相互指向,則會形成環 那麽對於一個聯通塊,我們可以只考慮雙向邊,直接使用dijstra,然後對從這個聯通塊發出的單向邊進行更新,更新其他聯通塊中的dist,然後把處理過的單向邊抹去。 因為是從s到其他點的距離,所以如果不是從一個聯通塊,沒有單向邊指向它,並且還不是s所在聯通塊,那麽它裏面的點都是無法到達的(顯然) ①所以,我們可以按照拓撲序進行更新,每處理完一個聯通塊,和其單向邊,我們就消除單向邊造成的入度,然後進行拓撲排序選擇聯通塊。 這樣寫法s所在聯通塊並不一定第一個入隊,但是其前入隊的聯通塊最短路無法更新,只能消除單向邊,寫法清晰。 ②我們也一開始可以就把s的聯通塊號傳入,這樣的話,其他入度為0的聯通塊指出的單向邊,我們直接需要將其抹去,消除無效聯通塊對其他聯通快造成的入度。 因為其他入度為0的聯通塊,是無效的。(代碼註釋部分) 技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 int t,r,p,s;
  5 typedef pair<int,int> pii;
  6 const int maxn = 5e4+5;
  7 vector<int>belong[maxn];
  8 struct Node
  9 {
 10     int x,y,val,next;
 11     Node(int x=0,int y=0,int val=0,int next=0):x(x),y(y),val(val),next(next) {}
 12 } node[2][maxn<<2];
 13 
 14 int head[2][maxn];
 15 int cnt[2];
 16 int tot;
 17 void add(int x,int y,int val,int t)
 18 {
 19     node[t][++cnt[t]].x = x;
 20     node[t][cnt[t]].y = y;
 21     node[t][cnt[t]].val = val;
 22     node[t][cnt[t]].next = head[t][x];
 23     head[t][x] = cnt[t];
 24 }
 25 int cn[maxn];
 26 int ind[maxn];
 27 int dist[maxn];
 28 bool vis[maxn];
 29 void dfs(int x)
 30 {
 31     cn[x] = tot;
 32     belong[tot].push_back(x);
 33     for(int i=head[0][x]; i; i=node[0][i].next)
 34     {
 35         int y = node[0][i].y;
 36         if(cn[y])
 37             continue;
 38         dfs(y);
 39     }
 40 }
 41 void solve(int s)
 42 {
 43     queue<int>que;
 44     while(!que.empty())
 45         que.pop();
 46     for(int i=1; i<=tot; i++)
 47         if(!ind[i])
 48             que.push(i);
 49 //    for(int i=1; i<=tot; i++)
 50 //    {
 51 //        if(!ind[i] && i != cn[s])
 52 //        {
 53 //            for(int j=0; j<belong[i].size(); j++)
 54 //            {
 55 //                for(int k=head[1][belong[i][j]]; k; k=node[1][k].next)
 56 //                {
 57 //                    --ind[cn[node[1][k].y]];
 58 //                }
 59 //            }
 60 //            ind[i] = -1;
 61 //            //printf("%d ------ %d\n",ind[i],i);
 62 //            i=0;
 63 //        }
 64 //    }
 65 //    que.push(cn[s]);
 66     memset(dist,0x3f,sizeof(dist));
 67     dist[s] = 0;
 68     priority_queue<pii,vector<pii>,greater<pii> >p;
 69     while(!que.empty())
 70     {
 71         int k = que.front();
 72         que.pop();
 73         while(!p.empty())
 74             p.pop();
 75         int len = belong[k].size();
 76         for(int i=0; i<len; i++)
 77         {
 78             if(dist[belong[k][i]] < 0x3f3f3f3f)
 79                 p.push(pii(dist[belong[k][i]],belong[k][i]));
 80         }
 81         while(!p.empty())
 82         {
 83             pii t = p.top();
 84             p.pop();
 85             if(vis[t.second])
 86                 continue;
 87             vis[t.second] = 1;
 88             for(int i=head[0][t.second]; i; i=node[0][i].next)
 89             {
 90                 if(dist[t.second] + node[0][i].val < dist[node[0][i].y])
 91                 {
 92                     dist[node[0][i].y] = dist[t.second] + node[0][i].val;
 93                     p.push(pii(dist[t.second] + node[0][i].val,node[0][i].y));
 94                 }
 95             }
 96             for(int i=head[1][t.second]; i; i=node[1][i].next)
 97             {
 98                 dist[node[1][i].y] = min(dist[node[1][i].y],dist[t.second]+node[1][i].val);
 99             }
100         }
101         for(int i=0; i<len; i++)
102         {
103             for(int j=head[1][belong[k][i]]; j; j=node[1][j].next)
104             {
105                 if(--ind[cn[node[1][j].y]] == 0)
106                     que.push(cn[node[1][j].y]);
107             }
108         }
109     }
110 }
111 
112 int main()
113 {
114     cnt[0] = cnt[1] = 0;
115     scanf("%d%d%d%d",&t,&r,&p,&s);
116     for(int i=1; i<=t; i++)
117         belong[i].clear();
118     for(int i=1; i<=r; i++)
119     {
120         int u,v,k;
121         scanf("%d%d%d",&u,&v,&k);
122         add(u,v,k,0);
123         add(v,u,k,0);
124     }
125 
126     for(int i=1; i<=p; i++)
127     {
128         int u,v,k;
129         scanf("%d%d%d",&u,&v,&k);
130         add(u,v,k,1);
131     }
132     tot = 0;
133     for(int i=1; i<=t; i++)
134     {
135         if(!cn[i])
136         {
137             tot++;
138             dfs(i);
139         }
140     }
141 
142 
143     for(int i=1; i<=cnt[1]; i++)
144     {
145         ind[cn[node[1][i].y]]++;
146     }
147     solve(s);
148     for(int i=1; i<=t; i++)
149     {
150         if(dist[i] == 0x3f3f3f3f)
151             printf("NO PATH\n");
152         else
153             printf("%d\n",dist[i]);
154     }
155 }
View Code

2200: [Usaco2011 Jan]道路和航線 (拓撲排序+dijstra)