HUD 3790 最短路径问题

13 篇文章 1 订阅

题目链接:最短路径问题

这道题是最短路问题的进阶版本

在求最短路的基础上增加了求花费这一操作

就是如果说存在多条最短长度相同的路径,选择花费最少的那一条路

做法就是再定义一个存图的二维数组,只不过存的不是两点之间的距离了,而是两点之间的花费

我觉得这不得用两个队列吗??如果说存在两条路,它们的路径上的点除了起点和终点相同,其余的都不相同,一条路的前半部分花费多,后半部分花费少,另一条路的前半部分花费少,后半部分的花费多,总的花费是第一条路的少

还需要考虑的问题是如何确定多个最短路

之前的最短路一个选一个就行了

这道题就是在最短路代码的基础上添加以下代码,如果说找到了到下一个点更短的路,就更新那个点的最短距离和花费
如果说存在多条到这个点相同且最小的长度的路径,则更新这几条路的最小花费

            for(int i=1;i<=n;i++){
			if(!vis[i]&&dis[i]>mp[k][i].x+dis[k]){
				dis[i]=mp[k][i].x+dis[k];
				cost[i]=mp[k][i].y+cost[k];
				que.push(Q(dis[i],i));
			}else if(!vis[i]&&dis[i]==mp[k][i].x+dis[k]){
				cost[i]=min(cost[i],mp[k][i].y+cost[k]);
				//cout<<"cost["<<i<<"]="<<cost[i]<<endl;
			}
		} 

关于细节性的问题:
 这道题与模板题不同的地方是多了一个花费的问题
花费和路径上本质上是相同的,只不过优先级比路径低,不用单独再开一个二维数组存值了,可以选择定义结构体

自己的小问题是,在main函数里忘了调用Init()

改过之后提交总超时,在main函数开头加咒语如下: 

ios::sync_with_stdio(false);

就能通过啦 

AC代码:

#include<iostream>
#include<cstring> 
#include<queue>
using namespace std;

typedef pair<int,int> Q; 
const int maxn=1010;
const int INF=0x3f3f3f3f;

struct p{
	int x;//距离 
	int y;//花费 
};

p mp[maxn][maxn];
bool vis[maxn];
int dis[maxn]; 
int cost[maxn];
int n,m;

int Init(){
	memset(vis,0,sizeof(vis));
	memset(dis,INF,sizeof(dis));
	memset(cost,INF,sizeof(cost));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j){
				mp[i][j].x=0;
				mp[i][j].y=0;
			}
			else{
				mp[i][j].x=INF;
				mp[i][j].y=INF;
			}
		}
	}
}

int dijkstra(int a){
	cost[a]=0;
	dis[a]=0;
	priority_queue<Q,vector<Q>,greater<Q> >que;
	que.push(Q(dis[a],a));
	while(!que.empty()){
		Q q=que.top();
		que.pop();
		int k=q.second;
		vis[k]=1;
		for(int i=1;i<=n;i++){
			if(!vis[i]&&dis[i]>mp[k][i].x+dis[k]){
				dis[i]=mp[k][i].x+dis[k];
				cost[i]=mp[k][i].y+cost[k];
				que.push(Q(dis[i],i));
			}else if(!vis[i]&&dis[i]==mp[k][i].x+dis[k]){
				cost[i]=min(cost[i],mp[k][i].y+cost[k]);
				//cout<<"cost["<<i<<"]="<<cost[i]<<endl;
			}
		} 
	}
}

int main(){
	ios::sync_with_stdio(false); 
	while(cin>>n>>m){
		if(n+m==0){
			break;
		}
		Init();
		int a,b,a1,b1,c,d;
		for(int i=0;i<m;i++){
			cin>>a1>>b1>>c>>d;
//			mp[a][b].x=c;
//			mp[a][b].y=d;
			if(mp[a1][b1].x>c){
				mp[a1][b1].x=c;
				mp[b1][a1].x=c;
				mp[a1][b1].y=d;
				mp[b1][a1].y=d;
			}else if(mp[a1][b1].x==c){
				if(mp[a1][b1].y>d){
					mp[a1][b1].y=d;
					mp[b1][a1].y=d;
				}
			}
		}
		cin>>a>>b;
		dijkstra(a);
//		for(int i=1;i<=n;i++){
//			cout<<dis[i]<<' '<<cost[i]<<'-'<<i<<endl;
//		}
		cout<<dis[b]<<' '<<cost[b]<<endl;
	}
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值