来源:Luogu P1073,JZOJ #317
题目描述
国有 个大城市和 条道路,每条道路连接这 个城市中的某两个城市。任意两个 城市之间最多只有一条道路直接相连。这 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为 条。
国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。
商人阿龙来到 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 国 个城 市的标号从 ,阿龙决定从 号城市出发,并最终在 号城市结束自己的旅行。在旅游的 过程中,任何城市可以重复经过多次,但不要求经过所有 个城市。阿龙通过这样的贸易方 式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另 一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 国旅游,他决定 这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。
假设 国有 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路 为单向通行,双向箭头表示这条道路为双向通行。 国有 个大城市和 条道路,每条道路连接这 个城市中的某两个城市。任意两个 城市之间最多只有一条道路直接相连。这 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为 条。 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。 商人阿龙来到 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 国 个城 市的标号从 ,阿龙决定从 号城市出发,并最终在 号城市结束自己的旅行。在旅游的 过程中,任何城市可以重复经过多次,但不要求经过所有 个城市。阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另 一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 国旅游,他决定 这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。 假设 国有 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路 为单向通行,双向箭头表示这条道路为双向通行。
解题思路
- 这是一道 的好题,思路是用邻接表存储图,单向边和双向边分开处理,开一个结构体数组 表示起点到点 水晶球的最小价格, 表示起点到点 最大盈利;
- 在 中,用两个变量 和 分别存储起点到点 原最小价格与当前第 个球的价格中的最小值;起点到点 原最大盈利与当前卖掉第 个球的盈利中的最大值。再拿 , 分别和 , 比较,更新最优解
代码君
#include <bits/stdc++.h>
using namespace std;
int t=0,n,m;
const int MAXN=100000*2+10,MAXM=500000*2+10; //数组范围
int vis[MAXN],q[MAXN],linkk[MAXM],p[MAXN];
struct node
{
int y,next;
}e[MAXN];
struct ANS
{
int minx;
int ans;
}a[MAXM];
void insert(int x,int y) //邻接表
{
e[++t].y=y;
e[t].next=linkk[x]; linkk[x]=t;
}
void SPFA(int st)
{
memset(vis,0,sizeof(vis));
vis[st]=1; a[1].minx=p[1]; a[1].ans=0; //初值
int head=1,tail=1;
q[head]=st; //起点进队
for (head=1;head<=tail;head++)
{
int x=q[head]; //取出队头
for (int i=linkk[x];i>0;i=e[i].next) //邻接表查询
{
int y=e[i].y; //当前边的终点
int Min=min(a[x].minx,p[x]); //比较x点价格是否更小
int Ans=max(a[x].ans,p[x]-a[x].minx); //如果在x点卖掉球是否盈利更大
if (Min<a[y].minx || Ans>a[y].ans)
{
if (Min<a[y].minx) //更新最小价格
{
a[y].minx=Min;
}
if (Ans>a[y].ans) //更新最大盈利
{
a[y].ans=Ans;
}
if(!vis[y]) //y点还没有标记
{
q[++tail]=y; //进队
vis[y]=1; //标记
}
}
}
vis[x]=0; //出队
}
}
void init()
{
freopen("trade.in","r",stdin);
freopen("trade.out","w",stdout);
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) cin >> p[i];
for (int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if (z==1) insert(x,y); //邻接表存储
else
{
insert(x,y);
insert(y,x);
}
}
}
int main()
{
init();
for (int i=1;i<=100005;i++) a[i].minx=0xfffffff,a[i].ans=-0xfffffff;
SPFA(1);
if (a[n].ans<0) printf("0"); //如果没有答案
else
printf("%d",a[n].ans);
return 0;
}