描述
C国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为1条。
C国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙来到C国旅游。当他得知“同一种商品在不同城市的价格可能会不同”这一信息之后,便决定在旅游的同时,利用商品在不同城市中的差价赚一点旅费。设C国 n 个城市的标号从 1~n,阿龙决定从1号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的过程中,任何城市可以被重复经过多次,但不要求经过所有 n 个城市。
阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另一个城市卖出这个水晶球,用赚取的差价当做旅费。因为阿龙主要是来C国旅游,他决定这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。
现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。
输入格式
第一行包含 2 个正整数n 和m,中间用一个空格隔开,分别表示城市的数目和道路的
数目。
第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这n 个城
市的商品价格。
接下来 m 行,每行有3 个正整数,x,y,z,每两个整数之间用一个空格隔开。如果z=1,表示这条道路是城市x 到城市y 之间的单向道路;如果z=2,表示这条道路为城市x 和城市y 之间的双向道路
输出格式
一个整数,表示答案。
样例输入
5 5 4 3 5 6 1 1 2 1 1 4 1 2 3 2 3 5 1 4 5 2
样例输出
5
数据范围与约定
- 输入数据保证 1 号城市可以到达n 号城市。
对于 10%的数据,1≤n≤6。
对于 30%的数据,1≤n≤100。
对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。
对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市
水晶球价格≤100。
测试地址:CH6101
如果题意莫名其妙,那么莫名其妙的不是出题人的脑袋就是我们的脑袋。——zrt
个人思路:
- 注意到进行最多一次、最多能赚取和输入格式,可以考虑一下单源最短路径。
- 假设我们是阿龙 的话,当然会在路径上选择最便宜的地方买物品,最贵的地方售出物品。
- 如果对Dijkstra的更新方式进行修改,就可以求出从源点到每一个点购入的最便宜价格。(对Dijkstra的理解)
- 形象地说,我们如果是阿龙的话,等于尝试走到每个点,并看从源点到每个点时,能购入的最便宜价格。
- 到这里,就有一个小技巧了。既然求得购入价格可以正着走,那么是否求售出价格可以反着走呢?
- 答案是可以的。
- 最终,进行两次Dijkstra,再枚举ans=max(售出价格[i]-购入价格[i])即可求出答案。注意,第二次Dijkstra要求进行在反图上。
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
int n;
struct Edge_Low{
int from,to,nxt;
}e_Low[MAXM];
int head_Low[MAXN],edgeCnt_Low=0;
void addEdge_Low(int u,int v){
e_Low[++edgeCnt_Low].from=u;
e_Low[edgeCnt_Low].to=v;
e_Low[edgeCnt_Low].nxt=head_Low[u];
head_Low[u]=edgeCnt_Low;
}
int price[MAXN];//各个点的价格
const int INF=2100000000;
struct Node{
int nowPoint,nowValue;
bool operator <(const Node &a)const{
return a.nowValue<nowValue;
}
};
int s_Low;
int dis_Low[MAXN];
void dijkstra_Low(){//收购尽量低价
for(int i=1;i<=n;i++)dis_Low[i]=INF;
priority_queue<Node> q;
q.push(Node{s_Low,price[s_Low]});dis_Low[s_Low]=price[s_Low];
while(!q.empty()){
Node nowNode=q.top();q.pop();
int nowPoint=nowNode.nowPoint,nowValue=nowNode.nowValue;
if(dis_Low[nowPoint]!=nowValue)continue;
for(int i=head_Low[nowPoint];i;i=e_Low[i].nxt){
int nowV=e_Low[i].to;
if(dis_Low[nowV]>dis_Low[nowPoint]){
dis_Low[nowV]=min(dis_Low[nowPoint],price[nowV]);
q.push(Node{nowV,dis_Low[nowV]});
}
}
}
}
struct Edge_High{
int from,to,nxt;
}e_High[MAXM];
int head_High[MAXN],edgeCnt_High=0;
void addEdge_High(int u,int v){
e_High[++edgeCnt_High].from=u;
e_High[edgeCnt_High].to=v;
e_High[edgeCnt_High].nxt=head_High[u];
head_High[u]=edgeCnt_High;
}
int s_High;
int dis_High[MAXN];
void dijkstra_High(){//售出尽量高价
for(int i=1;i<=n;i++)dis_High[i]=-INF;
priority_queue<Node> q;
q.push(Node{s_High,price[s_High]});dis_High[s_High]=price[s_High];
while(!q.empty()){
Node nowNode=q.top();q.pop();
int nowPoint=nowNode.nowPoint,nowValue=nowNode.nowValue;
if(dis_High[nowPoint]!=nowValue)continue;
for(int i=head_High[nowPoint];i;i=e_High[i].nxt){
int nowV=e_High[i].to;
if(dis_High[nowV]<dis_High[nowPoint]){
dis_High[nowV]=max(dis_High[nowPoint],price[nowV]);
q.push(Node{nowV,dis_High[nowV]});
}
}
}
}
int main(){
int m;
scanf("%d%d",&n,&m);
s_Low=1,s_High=n;
for(int i=1;i<=n;i++)scanf("%d",&price[i]);
for(int i=1;i<=m;i++){
int u,v,z;
scanf("%d%d%d",&u,&v,&z);
addEdge_Low(u,v);
addEdge_High(v,u);
if(z==2){
addEdge_Low(v,u);
addEdge_High(u,v);
}
}
dijkstra_Low();
dijkstra_High();
int ans=-INF;
for(int i=1;i<=n;i++)ans=max(ans,dis_High[i]-dis_Low[i]);
printf("%d
",ans);
return 0;
}