浙大复试-最短路径问题

求两点的最短路径

题目描述
给你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)

输出描述:

输出 一行有两个数, 最短距离及其花费。

示例1
输入

3 2
1 2 5 6
2 3 4 5
1 3
0 0

输出

9 11

思路分析

一道典型的Dijkstra问题,求两点之间的最短路径
1、需要邻间表,使用vector储存
2、把所有点到源点s的距离记录在dis数组里,把花费记录在cost数组里。
3、思路:Dijkstra简单来说就是定义两个集合S和T,S代表源点,T代表剩余的点,每次都把T中到源点最小距离的点加入S,更新dis数组和cost数组即可。比如0–1距离1,0–2距离5,1–2距离2,求0到2的最短路径。首先把01,02遍历,记录dis[1]=1和dis[2]=5,此时T中距离源点0最小距离的点是1,把1加入S,然后从1开始遍历与它相邻的边,发现12相连,则此时的话到2有两条路径,0-1-2和0-2,只需要比较dis[1]+2与dis[2]的大小,取小的即是0-2的最短路径。花费则同理。

如何每次都取出T中距离源点最小距离的点呢?每次求完都排序一次吗?
其实可以使用优先队列,将集合T中的定点到源点的距离作为这些点的优先级

因此我们需要

两个结构体

struct Edge{
	int length;
	int to;  //不需要from是因为 邻间表的下标就是from
	int price;
	Edge(int t,int len,int p):to(t),length(len),price(p){}
};
struct Point{
	int distance;//该点到源点的距离 
	int number; //当前编号 
	Point(int d,int n):distance(d),number(n){	}
	bool operator< (const Point& p)const{
		return distance>p.distance;  //距离最近优先级最大 
	}
}; 

邻间表的存储

vector<Edge> graph[MAXN];
******主函数内
while(m--) //填充邻间表
		{
			int from,to,length,price;
			scanf("%d%d%d%d",&from,&to,&length,&price);
			graph[from].push_back(Edge(to,lenght,price));  //无向图,两个点都需要加
			graph[to].push_back(Edge(from,length,price));
		} 

Dijkstra算法

void Dijkstra(int s)  //把所有点到s的距离记录在dis数组中 
{
	priority_queue<Point> myQ;
	dis[s]=0;
	cost[s]=0;
	myQ.push(Point(dis[s],s)); //压入一个点
	while(!myQ.empty()) //当队列不空
	{
		Point current=myQ.top();  //取出优先级最高的点
		int u=current.number;  //点的编号
		myQ.pop();
		for(int i=0;i<graph[u].size();i++) //遍历与该点相连的所有点,更新dis和cost数组
		{
			int v=graph[u][i].to;
			int d=graph[u][i].length;
			int p=graph[u][i].price;
			if(dis[v]>dis[u]+d||(dis[v]==dis[u]+d&&cost[v]>cost[u]+p)) //判断条件 ----通过点u是否使得从源点到v的距离缩短
			{
				dis[v]=dis[u]+d;
				cost[v]=cost[u]+p;
				myQ.push(Point(dis[v],v));
			}
		} 
	}
}

大功告成—
最后写几个注意的地方
1、在hdu上提交时超时,找了半天不知道错误在哪,后来发现是c++的cin函数的关系,所以以后这种题目都用scanf
2、填充函数
fill(dis,dis+n,INF),把dis数组全部初始化成最大值
memset(graph,0,sizeof(graph)), 把graph数组初始化为0 ----头函数#include<string.h> 牛客网会报错。。
一般来说,初始化0使用memest,fill可以无限制使用,前提得知道初试地址和末地址

完整代码

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<climits> 
using namespace std;
const int MAXN=1001;
const int INF=INT_MAX;
struct Edge{
	int length;
	int to;
	int price;
	Edge(int t,int len,int p):to(t),length(len),price(p){
		
	}
};
struct Point{
	int distance;//该点到源点的距离 
	int number; //当前编号 
	Point(int d,int n):distance(d),number(n){	}
	bool operator< (const Point& p)const{
		return distance>p.distance;  //距离最远优先级最小 
	}
}; 
vector<Edge> graph[MAXN];
int dis[MAXN];
int cost[MAXN];
void Dijkstra(int s)  //把所有点到s的距离记录在dis数组中 
{
	priority_queue<Point> myQ;
	dis[s]=0;
	cost[s]=0;
	myQ.push(Point(dis[s],s));
	while(!myQ.empty())
	{
		Point current=myQ.top();  //取出离s最近的点
		int u=current.number;
		myQ.pop();
		for(int i=0;i<graph[u].size();i++)
		{
			int v=graph[u][i].to;
			int d=graph[u][i].length;
			int p=graph[u][i].price;
			if(dis[v]>dis[u]+d||(dis[v]==dis[u]+d&&cost[v]>cost[u]+p))
			{
				dis[v]=dis[u]+d;
				cost[v]=cost[u]+p;
				myQ.push(Point(dis[v],v));
			}
		} 
	}
}
int main()
{

	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(!m&&!n) break;
		fill(dis,dis+n+1,INF);
		fill(cost,cost+n+1,INF);
		memset(graph,0,sizeof(graph));
		while(m--) //填充邻间表
		{
			int A,B,X,P;
			scanf("%d%d%d%d",&A,&B,&X,&P);
			graph[A].push_back(Edge(B,X,P));
			graph[B].push_back(Edge(A,X,P));
		} 
		int s,t;
		scanf("%d%d",&s,&t);
		Dijkstra(s);
		printf("%d %d\n",dis[t],cost[t]);
	}
	return 0;
} 
发布了8 篇原创文章 · 获赞 0 · 访问量 145
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 1024 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览