題目描述
一張圖,有由t個節點,r條雙向邊和p條單向邊組成,每條邊有邊權且可能存在負權,求能否從s到達每個節點並且輸出最小花費。
思路首先第一想法,把這張圖建出來,在跑一遍spfa即可,然而它顯然被卡了,不過似乎可以用雙端佇列優化水過去。
接下就是正解。我們考慮對於所有的道路,都是正權,我們可以用dijkstra做,而對於航線,不存在環。因此,如果我們將道路相連的連通圖縮點之後,得到必定是dag,而dag顯然可以用拓撲排序更新最短路。
所以我們只需要先把雙向邊的圖建出來,跑一遍tarjan縮點,再進行toposort,每次更新時把連通塊中所有節點都加入dijkstra的優先佇列中,對於每個點進行更新dis陣列。在進行dijkstra時把單向邊也更新一遍即可。
**
#includeusingnamespace
std;
const
int n=250020,m=1e5+10
;const
int inf=0x3f3f3f3f
;int
head[n],tot,to[m],nxt[m],w[m];
void add_edge(int x,int y,int z) //
雙向邊建圖
intdfn[n],top,idx,st[n],low[n];
intco[n],col;
vector
g[n];
bool
vis[n];
void tarjan(int u) //
tarjan縮點
else low[u]=min(low[u],dfn[v]);
}if(low[u]==dfn[u])
top--;
}}int
dis[n];
priority_queue
int,int> >q;
queue
que;
int fir[n],cnt,nex[m],ed[m],c[m],in
[n];
void add(int x,int y,int z) //
單向邊建圖
void
dijkstra()
}for(int i=fir[u];i;i=nex[i]) //
更新單向邊
}}void toposort(int
s) dijkstra();
}}int
read()
while(ch>='
0'&&ch<='9')
return res*w;
}void write(int
x)
if(x>9)write(x/10
); putchar(x%10^48);}
void writeln(int
x)int
main()
for(int i=1;i<=t;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=p;i++)
toposort(s);
for(int i=1;i<=t;i++)
if(dis[i]==inf)puts("
no path");
else
writeln(dis[i]);
}
道路和航線
試題描述 farmer john 正在乙個新的銷售區域對他的牛奶銷售方案進行調查。他想把牛奶送到 t 1 t 2.5 10 4 個城鎮 編號為 1 到 t。這些城鎮之間通過 r 條道路 編號為 1 到 r 和 p 條航線 編號為 1 到 p 連線。每條道路 i 或者航線 i 連線城鎮 ai到 bi,...
道路和航線 題解
題目描述 farmer john 正在乙個新的銷售區域對他的牛奶銷售方案進行調查。他想把牛奶送到 t 個城鎮 編號為 1 到 t 這些城鎮之間通過 r 條道路 編號為 1 到 r 和 p 條航線 編號為 1 到 p 連線。每條道路 i 或者航線 i 連線城鎮 a i 到 b i 花費為 c i 對於...
道路與航線
農夫約翰正在乙個新的銷售區域對他的牛奶銷售方案進行調查。他想把牛奶送到t個城鎮,編號為1 t。這些城鎮之間通過r條道路 編號為1到r 和p條航線 編號為1到p 連線。每條道路 ii 或者航線 ii 連線城鎮ai到bi,花費為ci。對於道路,0 ci 10,0000 ci 10,000 然而航線的花費...