今日推荐文章:https://cloud.tencent.com/developer/article/2473454?policyId=20240001&traceId=01jesnm005djmn2rgw9gnazq7b 在用户量庞大的应用系统中,如何进行系统的云原生架构是一件很有挑战的事情,本文以实践案例介绍了宝贵的架构经验,值得好好学习
这道题是一道隐藏的最短路问题,但是它又蕴含着很多细节值得我们考虑,看了很多人的博客,都只是浅浅地说可以用spfa算法,但是求单源最短路问题还有Dijsktra算法,为什么这道题不能用Dijsktra算法呢,下面是本人的一些理解。
首先看题目: https://www.luogu.com.cn/problem/P1073 最优贸易 - 洛谷
题意很简单,就是阿龙从1号城市出发,中间可以经过任何一个城市,且一个城市可以经过两次,完了可以进行一次买入与一次卖出交易,求最后获取交易的最大值。
完了我们思考,假设阿龙在 i 城市买入水晶球,在城市 j 卖出水晶球,那么也就是说,阿龙从起点走到城市 i 的路程上买水晶球的最少价格就是price i ,从城市 j 走到终点的路程上卖出水晶球的最多价格就是price j ,也就是说,我们可以把整个路程划分为下面三个部分:
这样看很直观得把整段路程分为了三部分,那么现在的核心就是如何求出每一段上的每个点对应的买入最小值,卖出最大值。
我们发现一段路程上,买入最小值永远都是所有已经经过点的最小值,卖出最大值永远都是未来经过点的最大值,于是我们想到了最短路求解,而我们要分别求最小值与最大值,于是我们可以求两边最短路,分别求正向的买入最小值minn i ,反向的卖出最大值maxn i ,这样枚举每一个点的差值,最大的差值就是最大交易收入
下面我们就要选择最短路算法,可能很多人想到了Dijsktra算法(我一开始也这样,完了WA了),但是,这道题卡掉了Dijsktra算法,为什么呢?
因为Dijsktra算法保证每个已经更新了最短距离的点后面距离就不会更新,但是在这道题中,假使你走到城市 i ,后面可能还会有买入价格更低的城市,这样必须还要更新,所以Dijsktra算法行不通,于是我们可以用SPFA算法,每次都将出队的点设置为未遍历,这样后面还会继续更新。
清楚了这两点之后,代码的书写就水到渠成了,下面附上源代码:
#include<iostream>
using namespace std;
#include<cstring>
#include<queue>
typedef pair<int,int> PII;
const int N = 1e5+10, M = 2e6+10, INF = 0x3f3f3f3f;
int hs[N],e[M],ne[M],w[M],idx;
int price[N],ht[N],n,m,dmax[N],dmin[N];
bool st[N];
void add(int h[],int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//flag为真表示求正向走路买入的最小值
void SPFA(int u,int h[],int dist[],bool flag){
memset(st,0,sizeof(st));
queue<int>q;
if(flag) memset(dist,0x3f,sizeof(dmax));
dist[u]=price[u];
q.push(u);
st[u]=true;
while(q.size()){
int t=q.front();
q.pop();
//每次出队后设置为未访问,保证后面距离能继续更新
st[t]=false;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if((flag&&dist[j]>min(price[j],dist[t]))||(!flag&&dist[j]<max(dist[t],price[j]))) {
if(flag) dist[j]=min(price[j],dist[t]);
else dist[j]=max(dist[t],price[j]);
if(!st[j]){
st[j]=true;
q.push(j);
}
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&price[i]);
memset(hs,-1,sizeof(hs));
memset(ht,-1,sizeof(ht));
int a,b,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
//建立反向图
add(hs,a,b),add(ht,b,a);
if(c==2) add(hs,b,a),add(ht,a,b);
}
//这里求最小值从1开始,求最大值从n开始
//因为结合路程图,我们是在1~i城市买入水晶球,在i~n城市卖出水晶球
//所以要从1开始求到达i之前买入水晶球最少价格
//从n开始求到达i之前能够卖出的最大价格,之后做差值
SPFA(1,hs,dmin,true);
SPFA(n,ht,dmax,false);
int res=0;
for(int i=1;i<=n;i++) res=max(res,dmax[i]-dmin[i]);
cout<<res<<endl;
return 0;
}
这就是这道题的全部内容了,值得思考的点还是很多的,希望各位有所收获!!!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。