乘車路線「二維spfa」
阿新 • • 發佈:2020-07-19
乘車路線「二維spfa」
題目描述
編號為 1
∼N
的 N
座城鎮用若干僅供單向行駛的道路相連,每條道路上均有兩個引數:道路長度(length
)和在該條道路上行駛的費用(cost
)。BOB準備從城鎮 1
出發到達城鎮 N
,但他目前只有 W
的錢,為此,你需要幫助他尋找一條從城鎮 1
到城鎮 N
在他能支付的前提下的一條最短路線。
輸入
W
N
M
(N
為城鎮數目,2
<=N
<=100
,M
為道路條數,1
<=M
<=10000
,W
為錢的數目,0
<=W
<=1000
)隨後的 M
行每行為一條道路的資訊,包含 4
個數值(u
,v
,w
,cost
),表示從城鎮 u
到 v
有一條長度為 w
的單向道路,經過這條道路需要花費 cost
1
<=u
,v
<=N
,1
<=w
<=100
,0
<=cost
<=100
)
輸出
輸出最短長度,若無解,則輸出“NO
”;
樣例輸入
5 6 7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
樣例輸出
11
思路分析
- 乍一眼看去,最短路啊,再看一眼,誒?有問題,還多了一個限制條件就離譜
- 考試時直接按邊權和錢數分別跑了兩遍spfa,後來才發現正確性是不對的(
更離譜的是竟然水過了80分,最離譜的是有人暴搜AC了???)。 - 那麼正確思路是什麼?兩個一起跑唄,一個二維spfa就彳亍,用到了一個本蒟蒻沒用過的pair
詳見程式碼
程式碼
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; const int maxn = 100+10,maxm = 1e4+10,inf = 0x3f3f3f3f; int w,n,m; int dis[maxn][1005],mon[maxn],ans[maxn],head[maxm],vis[maxn][1005]; struct edge{ int to,next,w,cost; }e[maxm]; int len; void addedge(int u,int v,int x,int y){ e[++len].to = v; e[len].w = x; e[len].cost = y; e[len].next = head[u]; head[u] = len; } void spfa(int x){ //注意dis,vis都開二維 memset(dis,0x3f,sizeof(dis)); queue< pair<int,int> >q; //佇列裡儲存的是pair dis[x][0] = 0; q.push(make_pair(x,0)); //用一個pair把dis和money一起壓進去 while(!q.empty()){ pair<int,int> t = q.front();q.pop(); int u = t.first,money = t.second; vis[u][money] = 0; for(int i = head[u];~i;i = e[i].next){ int v = e[i].to; if(money+e[i].cost>w)continue; //錢不夠跑 if(dis[v][money+e[i].cost]>dis[u][money]+e[i].w){ //錢夠跑並且可以鬆弛 dis[v][money+e[i].cost]=dis[u][money]+e[i].w; if(!vis[v][money+e[i].cost]){ vis[v][money+e[i].cost] = 1; q.push(make_pair(v,money+e[i].cost)); } } } } } int main(){ scanf("%d%d%d",&w,&n,&m); memset(head,-1,sizeof(head)); for(int i = 1;i <= m;i++){ int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d); addedge(a,b,c,d); } spfa(1); int ans = inf; for(int i = 0;i <= w;i++)ans = min(ans,dis[n][i]); ans==inf ? printf("NO") : printf("%d",ans); return 0; }