最短路径问题(HDU 3790)

题目链接

题目描述

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入格式

输入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)

输出格式

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

输入样例

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

输出样例

9 11

分析

二维费用的最短路,在套用模板的时候多加一个判断更新最小费用就行了,以下是分别用Dijkstra,SPFA,SPFA(SLF优化)算法的源码。

源程序

Dijkstra算法

#include <bits/stdc++.h>
#define MAXN 1005
#define MAXM 100005
using namespace std;
struct Edge{	//链式前向星建图 
	int v,w,c,next;
	Edge(){};
	Edge(int _v,int _w,int _c,int _next){
		v=_v,w=_w,c=_c,next=_next;
	};
	bool operator <(const Edge a)const{
		if(w!=a.w)return w>a.w;
		else return c>a.c;
	}
}edge[MAXM*2];
int EdgeCount,head[MAXN];
int n,m,s,t,dis[MAXN],cost[MAXN];
bool used[MAXN];
void addEdge(int u,int v,int w,int c)	//链式前向星加边 
{
	edge[++EdgeCount]=Edge(v,w,c,head[u]);
	head[u]=EdgeCount;
}
void dijkstra()
{
	memset(dis,0x3f,sizeof(dis));	//初始化 
	memset(cost,0x3f,sizeof(cost));
	memset(used,false,sizeof(used));
	priority_queue<Edge> q;
	dis[s]=cost[s]=0;
	q.push(Edge{s,0,0,0});
	while(!q.empty()){
		int u=q.top().v;q.pop();
		if(used[u])continue;	//如果已经确定最短路就continue 
		used[u]=true;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w,c=edge[i].c;
			if(dis[v]>dis[u]+w){	//找到新的最短路 
				dis[v]=dis[u]+w;
				cost[v]=cost[u]+c;
				q.push(Edge{v,dis[v],cost[v],0});
			}
			else if(dis[v]==dis[u]+w){	//找到新的最短路最小费用 
				if(cost[v]>cost[u]+w){
					cost[v]=cost[u]+c;
				}
			}
		}
	}
	return ;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&(n||m)){
		memset(head,0,sizeof(head));	//初始化 
		EdgeCount=0;
		for(int i=1;i<=m;i++){	//读入数据 
			int u,v,w,c;
			scanf("%d%d%d%d",&u,&v,&w,&c);
			addEdge(u,v,w,c);
			addEdge(v,u,w,c);
		}
		scanf("%d%d",&s,&t);	//读入起点和终点 
		dijkstra();
		printf("%d %d\n",dis[t],cost[t]);
	}
}

SPFA算法

#include <bits/stdc++.h>
#define MAXN 1005
#define MAXM 100005
using namespace std;
struct Edge{
	int v,w,c,next;
	Edge(){};
	Edge(int _v,int _w,int _c,int _next){
		v=_v,w=_w,c=_c,next=_next;
	};
}edge[MAXM];
int EdgeCount,head[MAXN];
int n,m,s,t,dis[MAXN],cost[MAXN];
int ven[MAXN],nums[MAXN];
void addEdge(int u,int v,int w,int c)
{
	edge[++EdgeCount]=Edge(v,w,c,head[u]);
	head[u]=EdgeCount;	
} 
void SPFA()
{
	memset(dis,0x3f,sizeof(dis));
	memset(cost,0x3f,sizeof(cost));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	queue<int> q;
	dis[s]=cost[s]=0;
	ven[s]=nums[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w,c=edge[i].c;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				cost[v]=cost[u]+c;
				if(!ven[v]){
					q.push(v);
					ven[v]=1;
//					nums[v]++;
//					if(nums[v]>n)return false;
				}
			}
			else if(dis[v]==dis[u]+w){
				if(cost[v]>cost[u]+c){
					cost[v]=cost[u]+c;
					if(!ven[v]){
						q.push(v);
						ven[v]=1;
//						nums[v]++;
//						if(nums[v]>n)return false;
					}
				}
			}
		}
	}
//	return true;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&(n||m)){
		memset(head,0,sizeof(head));
		EdgeCount=0;
		for(int i=1;i<=m;i++){
			int u,v,w,c;
			scanf("%d%d%d%d",&u,&v,&w,&c);
			addEdge(u,v,w,c);
			addEdge(v,u,w,c);
		}
		scanf("%d%d",&s,&t);
		SPFA();
		printf("%d %d\n",dis[t],cost[t]);
	}
}

SPFA算法之SLF优化

#include <bits/stdc++.h>
#define MAXN 1005
#define MAXM 100005
using namespace std;
struct Edge{	//链式前向星 
	int v,w,c,next;
	Edge(){};
	Edge(int _v,int _w,int _c,int _next){
		v=_v,w=_w,c=_c,next=_next;
	};
}edge[MAXM];
int EdgeCount,head[MAXN];
int n,m,s,t,dis[MAXN],cost[MAXN];
int ven[MAXN],nums[MAXN];
void addEdge(int u,int v,int w,int c) //链式前向星加边 
{
	edge[++EdgeCount]=Edge(v,w,c,head[u]);
	head[u]=EdgeCount;	
} 
void SPFA()
{
	memset(dis,0x3f,sizeof(dis));	//初始化 
	memset(cost,0x3f,sizeof(cost));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	deque<int> q;
	dis[s]=cost[s]=0;
	ven[s]=nums[s]=1;
	q.push_back(s);
	int cnt;
	while((cnt=q.size())){
		int u=q.front();q.pop_front();
		ven[u]=0;	//取消队列标记 
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w,c=edge[i].c;
			if(dis[v]>dis[u]+w){	//更新最短路 
				dis[v]=dis[u]+w;
				cost[v]=cost[u]+c;
				if(!ven[v]){	//不在队列中 
					if(cnt>1&&dis[v]<dis[q.front()])q.push_front(v);
					else q.push_back(v); 
					ven[v]=1;
//					nums[v]++;
//					if(nums[v]>n)return false;
				}
			}
			else if(dis[v]==dis[u]+w){	//更新最短路最小费用 
				if(cost[v]>cost[u]+c){
					cost[v]=cost[u]+c;
				}
			}
		}
	}
//	return true;
}
int main()
{
	while(scanf("%d%d",&n,&m)&&(n||m)){
		memset(head,0,sizeof(head));	//初始化 
		EdgeCount=0;
		for(int i=1;i<=m;i++){	//读入数据 
			int u,v,w,c;
			scanf("%d%d%d%d",&u,&v,&w,&c);
			addEdge(u,v,w,c);
			addEdge(v,u,w,c);
		}
		scanf("%d%d",&s,&t);	//读入起点和终点 
		SPFA();
		printf("%d %d\n",dis[t],cost[t]);
	}
}
发布了19 篇原创文章 · 获赞 0 · 访问量 125

猜你喜欢

转载自blog.csdn.net/weixin_43960284/article/details/105269428