-
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
-
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t) -
输出 一行有两个数, 最短距离及其花费。
-
3 2 1 2 5 6 2 3 4 5 1 3 0 0
-
9 11
- 思路:
- 本题思路比较简单,就是一个单纯的最短路问题,不过稍微拐弯一点的地方就是本题有两个条件,一个是距离一个是花费,只要把这个地方处理好,基本没什么问题。
-
具体代码:
-
#include <iostream> #include <queue> #include <vector> using namespace std; struct Edge { int from,to; int dist; int cost; Edge(int tf,int tt,int td,int tc):from(tf),to(tt),dist(td),cost(tc){} }; struct HeadNode { int v; int d; int p; HeadNode(int tv,int td,int tp):v(tv),d(td),p(tp){} //注意此处有两个条件 bool operator < (const HeadNode& rhs) const { if(d==rhs.d) return p>rhs.p; //注意是大于,因为priority_queue是大根堆 else return d>rhs.d; } }; const int maxn=1000+5; const int INF=1000000000; struct Dij { int n,m; vector<Edge> edges; vector<int> G[maxn]; bool done[maxn]; int d[maxn]; int p[maxn]; int path[maxn]; void init(int tn) { n=tn; edges.clear(); for(int i=0;i<n;++i) G[i].clear(); } void addEdge(int tu,int tv,int td,int tc) { edges.push_back(Edge(tu,tv,td,tc)); m=edges.size(); G[tu].push_back(m-1); } void dijkstra(int s) { fill(done,done+n,false); fill(d,d+maxn,INF); priority_queue<HeadNode> pq; d[s]=0; p[s]=0; pq.push(HeadNode(s,0,0)); while(!pq.empty()) { HeadNode t=pq.top();pq.pop(); int u=t.v; if(done[u]) continue; for(int i=0;i<G[u].size();++i) { Edge& e=edges[G[u][i]]; //注意有两个条件时如何松弛 if(d[e.to]>d[u]+e.dist||d[e.to]==d[u]+e.dist&&p[e.to]>p[u]+e.cost) { d[e.to]=d[u]+e.dist; p[e.to]=p[u]+e.cost; path[e.to]=G[u][i];//最短路上当前结点的上一条弧,本题用不到 pq.push(HeadNode(e.to,d[e.to],p[e.to])); } } } } }; Dij dij; int main() { int n,m; for(cin>>n>>m;n!=0||m!=0;cin>>n>>m) { dij.init(n); for(int i=0;i<m;++i) { int a,b,d,p; cin>>a>>b>>d>>p; dij.addEdge(a,b,d,p); } int s,des; cin>>s>>des; dij.dijkstra(s); cout<<dij.d[des]<<" "<<dij.p[des]<<endl; } return 0; }
题目描述:
-
输入:
-
输出:
-
样例输入:
-
样例输出: