7-13 森森旅游 (30 分)(迪杰斯特拉+multiset)(代码有解析)

/*
解题思路:
森森从1到达n,可能会在中途点t(也可以是1或者n)换取旅游金 ;
如果在t点换完以后,那么后面的旅途只能用旅游金,那么我们可以在
1—t用最少现金(第一个迪杰斯特拉),t-n用最少旅游金(第二个)
所以正向建一个最短路径得到1到t的最小权,反向建一个得到t到n的最小权;
这里的迪杰斯特拉要用优先队列来进行迪杰斯特拉,因为题目说 点a到b可能不止一条路! 

两个最小路径建完以后,把1——n上的所有点都作为换取旅行金的点,进行计算总花费金额 
把每个点作为换取点后,所需总金额放进一个multiset容器(看完代码你会知道为什么是multiset) 

再每一次更新汇率后,也更新multiset里面的值。 
*/

单源最短路径 Dijkstra+优先队列_Meloor的博客-CSDN博客

C++优先队列自定义排序总结_KRYON!的博客-CSDN博客_优先队列自定义排序

/*
解题思路:
森森从1到达n,可能会在中途点t(也可以是1或者n)换取旅游金 ;
如果在t点换完以后,那么后面的旅途只能用旅游金,那么我们可以在
1—t用最少现金(第一个迪杰斯特拉),t-n用最少旅游金(第二个)
所以正向建一个最短路径得到1到t的最小权,反向建一个得到t到n的最小权;
这里的迪杰斯特拉要用优先队列来进行迪杰斯特拉,因为题目说 点a到b可能不止一条路! 

两个最小路径建完以后,把1——n上的所有点都作为换取旅行金的点,进行计算总花费金额 
把每个点作为换取点后,所需总金额放进一个multiset容器(看完代码你会知道为什么是multiset) 

再每一次更新汇率后,也更新multiset里面的值。 
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const long long INF=1e18;
typedef pair<int,long long> P;//没用上 
typedef long long LL;
struct node{ 		 
	int id;
	LL cost;
	friend int operator <(const struct node &a,const struct node &b) //使得优先队列中cost最小的优先 
	{
		return a.cost>b.cost;
	}
};
vector<node> T1[maxn],T2[maxn];//存图 
int n,m,o,a,b,vis1[maxn],vis2[maxn];//vis用于标记 
LL w1,w2,huan[maxn],tran[maxn],D1[maxn],D2[maxn];//D用来存最短权值 ,tran存放可达点的总金额 
void djs(int a,LL D[],vector<node> T[],int vis[])
{
	priority_queue<node> que;
	fill(D+1,D+n+1,INF);
	D[a]=0;
	que.push({a,0});
	while(!que.empty())
	{
		int p=que.top().id;
		que.pop();
		if(vis[p]) continue;
		vis[p]=1;
		for(int i=0;i<T[p].size();i++)
		{
			int u=T[p][i].id;
			LL w=T[p][i].cost;
			if(D[u]>D[p]+w)
			{
				D[u]=D[p]+w;
				que.push({u,D[u]});
			}
		}
	}
}
int main(void)
{
	scanf("%d%d%d",&n,&m,&o);
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%lld%lld",&a,&b,&w1,&w2);
		T1[a].push_back({b,w1});//正向图 
		T2[b].push_back({a,w2});//反向图 
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&huan[i]);
	}
	djs(1,D1,T1,vis1);
	djs(n,D2,T2,vis2);
	
	multiset<LL> ma;
	for(int i=1;i<=n;i++)
	{
		if(D1[i]==INF||D2[i]==INF) continue;//i点不可达 
		// (D2[i]+huan[i]-1)/huan[i])  的意思如下  
		//如果汇率是8,t-n花费的旅游金是39,那么39/8=4,但是4*8=32,那就不对了,花费的钱应该是5; 
		ma.insert(tran[i]=D1[i]+(D2[i]+huan[i]-1)/huan[i]);//tran[i]存放可达点的总金额 
	}
	while(o--)
	{
		int xi;
		LL ai;
		scanf("%d%lld",&xi,&ai);
		if(!tran[xi]||huan[xi]==ai)//如果xi点不可达或者xi点的汇率和之前一样 
		{
			printf("%lld\n",*ma.begin());
		}
		else
		{
			ma.erase(ma.find(tran[xi]));
			huan[xi]=ai;
			ma.insert(tran[xi]=D1[xi]+(D2[xi]+huan[xi]-1)/huan[xi]);
			printf("%lld\n",*ma.begin());
		}
	}
	return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头秃不是梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值