1020. Tree Traversals (25)多权最短路,和单权是一样的

本文介绍了一种解决多权最短路径问题的方法,即在确保路径距离最短的前提下找到成本最低的路径。通过绑定距离和成本为单一权重并利用Dijkstra算法进行求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="font-size:48px;"><strong>1020. Tree Traversals (25)</strong></span>
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (<=500) is the number of cities (and hence the cities are numbered from 0 to N-1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
Sample Output
0 2 3 3 40
    最简单的多权最短路问题,内容抽象一下就是给你起点和终点,边以及边的距离和每条边的消费,希望你在保证距离最短的情况下给出消费最少的解法。最简单的方法是直接把边的距离和边的消费绑定成 weight = dist*k - cost;k的值应当保证cost不会影响到dist直接的比较,同时weight也不会溢出,这样问题就转换成了普通的最短路问题,当然,多数人的选择应该是是使用dijkstra时多加几个 if 的判断条件,但是条件多代码就很难看。而难看真的是不能容忍的。比较优雅的做法是做一个weight类,重载<,=,+ <= 等操作符,这样就可以愉快地使用dijkstra算法了,同时主体代码会比较干净。
翻了一下从前的提交,发现我用的果然是最懒的解法,呵呵
# include <cstdio>
# include <cstring>
# include <climits>
# include <queue>
# include <algorithm>
using namespace std;

const int _size = 500;
int Dist[_size][_size];
typedef pair<int,int> dist;
int dis[5000];
int pre[5000];
int main()
{
  int n,m,s,e;
  scanf("%d%d%d%d",&n,&m,&e,&s);
  for (int i=0;i<n;i++)
     for (int j=0;j<n;j++)
         Dist[i][j] = INT_MAX/4;
  memset(pre,-1,sizeof(pre));
  while (m--)
  {
      int a,b,c,d;
      scanf("%d%d%d%d",&a,&b,&c,&d);
      Dist[a][b] = Dist[b][a] = c*10000 + d;
  }
  priority_queue<dist,vector<dist>,greater<dist> > h;
  for (int i=0;i<n;i++)
      dis[i] = INT_MAX/4;


  dis[s] = 0;
  int f = -1,c = s;
  h.push(dist(dis[s],s));
  while (!h.empty())
  {
      dist loca = h.top();h.pop();
      int city = loca.second;
      if (dis[city] < loca.first)  continue;
      for (int i=0;i<n;i++)
      {
      	if (dis[city] + Dist[city][i] < dis[i])
	      {
		      dis[i] = dis[city] + Dist[city][i];pre[i] = city;
		      h.push(dist(dis[i],i));
	      }
	  }
  }
  f = e;
  while (f!=-1)
  {
      printf("%d ",f);
      f = pre[f];
  }
  printf("%d %d\n",dis[e]/10000,dis[e]%10000);
  return 0;
}

然而这份代码在牛客网上貌似是无法通过的,所以勤奋的我又用写一个wight类的思想,再写了一份代码
# include <cstdio>
# include <climits>
# include <iostream>
# include <algorithm>
# include <queue>
# include <stack>
using namespace std;

struct weight
{
  int lenth,cost;
  weight(int _lenth = (INT_MAX>>1),int _cost = 0):lenth(_lenth),cost(_cost){}
  weight operator + (weight& oper)
  {
      return weight(lenth + oper.lenth,cost + oper.cost);
  }
  bool operator < (const weight& oper) const 
  {
      if (lenth!=oper.lenth)
          return lenth < oper.lenth;
      return cost < oper.cost;
  }
  void Read()
  {
      cin >> lenth >> cost;
  }
};
struct edge
{
    int to;
    weight value;
    edge *next;
    edge(int _to,weight& _w):to(_to),value(_w),next(NULL){}
};
struct vertex 
{
   weight w_sum;
   int prev;
   edge *next,*last;
   vertex():prev(-1),next(NULL),last(NULL){}
   void Attach(int _to,weight& _value)
   {
       if (next == NULL)
           next = last = new edge(_to,_value);
       else 
           last = last->next = new edge(_to,_value);
   }
};
vertex city[501];
int main()
{
  int n,m,s,e;
  cin >> n >> m >> s >> e;
  while (m--)
  {
    int a,b;
    weight temp;
    cin >> a >> b;
    temp.Read();
    city[a].Attach(b,temp);
    city[b].Attach(a,temp);
  }
  typedef pair<weight,int> p;
  priority_queue<p,vector<p>,greater<p> > pq;
  city[s].w_sum.lenth = 0;
  pq.push(p(city[s].w_sum,s));
  while (!pq.empty())
  {
    p loca = pq.top();pq.pop();
    int c = loca.second;
    weight w = loca.first;
    if (city[c].w_sum < w) 
        continue;
    edge *next = city[c].next;
    while (next)
    {
	    if (w + next->value < city[next->to].w_sum)
	        {
			    city[next->to].w_sum= w + next->value;
			    pq.push(p(city[next->to].w_sum,next->to));
			    city[next->to].prev = c; 
			}
		next = next->next;
	}
  }
  stack<int> stac;
  int temp = e;
  stac.push(e);
  while (city[temp].prev!=-1)
  {
      stac.push(city[temp].prev);
      temp = city[temp].prev;
  }
  while (!stac.empty())
  {
      cout << stac.top() << ' '; 
      stac.pop();
  }
  cout << city[e].w_sum.lenth << ' ' << city[e].w_sum.cost << endl;
  return 0;
}

图的实现略繁,这是我从前的写法,现在的话应该是果断一个vector<edge>就解决了,同时我并不能理解为什么第二种方法内存开销较小



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值