Total Submission(s): 12921 Accepted Submission(s): 3940
Problem Description
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
(1<n<=1000, 0<m<100000, s != t)
Output
输出 一行有两个数, 最短距离及其花费。
Sample Input
3 2 1 2 5 6 2 3 4 5 1 3 0 0
Sample Output
9 11
Total Submission(s): 12921 Accepted Submission(s): 3940
Problem Description
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
(1<n<=1000, 0<m<100000, s != t)
Output
输出 一行有两个数, 最短距离及其花费。
Sample Input
3 2 1 2 5 6 2 3 4 5 1 3 0 0
Sample Output
9 11
题意就是输出路程最短的,路程最短的有多条则输出最省钱的。所以只需要在更新路程d[i]的时候顺带更新花费fare[i]
。然后当
还有一点就是必须赋f[src]=0,不然也是错的,跟赋d[src]=0同一个道理。
d[v[i]]==d[u]+w[i]的时候如果满足
fare[v[i]]>fare[u]+f[i], 就更新花费即可。
中间有一段是用SPFA算的。两种均可。
其实1个最小,2个最小和3个最小都是一样的,也行以后还会多一个其他花费,比如其他等等。同理可得。
<span style="color:#330033;">#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <stack> using namespace std; typedef pair<int ,int>pii; const int maxn = 1030; const int maxm = 200010; const int inf = 0x3f3f3f3f; int v[maxm],next[maxm],w[maxm]; int first[maxn],d[maxn],inq[maxn],e,i,f[maxm],fare[maxn]; //queue<int> q; void init(){ e = 0; memset(first,-1,sizeof(first)); } void add_edge(int a,int b,int c,int g){ v[e] = b;next[e] = first[a];w[e] = c;f[e]=g;first[a] = e++;</span>
<span style="color:#330033;">//要特地开一个数组用于记录花费,跟记录路程一样 } /*void spfa(int src){ memset(d,0x3f,sizeof(d)); d[src] = 0,inq[src] = 1; fare[0]=0; q.push(src); while(!q.empty()){ int u = q.front(); q.pop(); inq[u] = 0; for(int i = first[u];i != -1;i = next[i]) { if(d[v[i]] > d[u]+w[i]) { d[v[i]] = d[u]+w[i]; fare[v[i] ]=fare[ u ]+f[i]; if(!inq[v[i]]) {q.push(v[i]);inq[v[i]] = 1;} } else if(d[v[i]] == d[u]+w[i]&&fare[v[i] ]>fare[ u ]+f[i]) { d[v[i]] = d[u]+w[i]; fare[v[i] ]=fare[ u ]+f[i]; if(!inq[v[i]]) {q.push(v[i]);inq[v[i]] = 1;} } } } } */ void dijstra(int src ) { priority_queue<pii,vector<pii>,greater<pii> > q; while(!q.empty()) q.pop(); memset(d,-1,sizeof(d)); d[src]=0; fare[src]=0; //必须赋值,跟赋d[src]同一个道理 q.push(make_pair(0,src)); while(!q.empty()) { while(!q.empty()&&q.top().first>d[q.top().second]) q.pop(); if(q.empty()) break; int u=q.top().second; q.pop(); for(i=first[u];i!=-1;i=next[i]) { if(d[v[i]]==-1||d[v[i]]>d[u]+w[i]) { d[v[i]]=d[u]+w[i]; fare[v[i]]=fare[u]+f[i]; q.push(make_pair(d[v[i]],v[i])); } else if(d[v[i]]==d[u]+w[i])//如果路程相等,取花费少的。 if(fare[v[i]]>fare[u]+f[i]) { fare[v[i]]=fare[u]+f[i]; q.push(make_pair(d[v[i]],v[i])); } } } } int main(){ int n,m,s,t,a,b,c,g,st,ed; while(scanf("%d%d",&n,&m)) {if(n==0&&m==0) break; init(); for(int i = 0;i < m;i++){ scanf("%d%d%d%d",&a,&b,&c,&g); add_edge(a,b,c,g); add_edge(b,a,c,g); } scanf("%d%d",&st,&ed); //spfa(st); dijstra(st); printf("%d %d\n",d[ed],fare[ed]); } return 0; }</span>程序第一次提交的时候竟然错了,找了半天发现是f[]开小了,开成了maxn.实际应该是maxm。因为它跟v数组都是共用e下标的,e是边数,所以应该是maxm。以后不管3721直接开maxm得了,如果超了再改小点。。免得出错。。
还有一点就是必须赋f[src]=0,不然也是错的,跟赋d[src]=0同一个道理。