C++图论SPFA算法例题———————最优贸易

 

题目描述:

C 国有

n个大城市和m 条道路,每条道路连接这n 个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为1 条。C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 C 国n 个城市的标号从1\sim n ,阿龙决定从1 号城市出发,并最终在n 号城市结束自己的旅行。在旅游的过程中,任何城市可以重复经过多次,但不要求经过所有n 个城市。阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品——水晶球,并在之后经过的另一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 C 国旅游,他决定这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。

假设 C 国有5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路为单向通行,双向箭头表示这条道路为双向通行。

27.png

假设

1~n 号城市的水晶球价格分别为4,3,5,6,1 。

阿龙可以选择如下一条线路:

1, 2, 3, 5 ,并在2 号城市以3 的价格买入水晶球,在3 号城市以5 的价格卖出水晶球,赚取的旅费数为2 。

阿龙也可以选择如下一条线路1, 4, 5, 4, 5 ,并在第1 次到达5 号城市时以1 的价格买入水晶球,在第2 次到达4 号城市时以6 的价格卖出水晶球,赚取的旅费数为5 。

现在给出n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。

输入:

输入第一行包含

2个正整数n 和m ,中间用一个空格隔开,分别表示城市的数目和道路的数目。

第二行n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这n 个城市的商品价格。

接下来m 行,每行有3 个正整数,x,y,z ,每两个整数之间用一个空格隔开。如果z=1 ,表示这条道路是城市x 到城市y 之间的单向道路;如果z=2 ,表示这条道路为城市x 和城市y 之间的双向道路。

输出:

输出共1行,包含1 个整数,表示最多能赚取的旅费。如果没有进行贸易,则输出0 。

输入样例:

5 5
4 3 5 6 1
1 2 1
1 4 1
2 3 2
3 5 1
4 5 2

输出样例:

5

 思路分析:

这一题通过思考就是求一条路径上每一点所能达到的最小购入值与最大的卖出值的差值。

但是我们该如何去求呢?

很简单,用一次SPFA用正图,求出每一点所能到的最小值(毕竟阿福是从1号节点开始的)。

那么,再用一遍SPFA用原图的逆图,就能求出每一点所能到的最大卖出值了。(反向操作,最为致命)。

最后再遍历了一遍每个点, 就有答案了。

代码实现:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=100005;
const int MAXM=500005;
const int INF=100000;
int N,M,np=0,np2=0,last[MAXN],last2[MAXN],MAX[MAXN],MIN[MAXN],in[MAXN],a[MAXN];
struct edge{
    int to,pre;
};
edge E[MAXM*2],G1[MAXM*2];
char c;
void read(int &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
}

void addedge(int u,int v)
{
	E[++np]=(edge){v,last[u]};
	last[u]=np;
}

void addedgG1(int u,int v)
{
	G1[++np2]=(edge){v,last2[u]};
	last2[u]=np2;
}

void spfa1()
{
	queue<int>q;
	for(int i=1;i<=N;i++) MIN[i]=INF;
	MIN[1]=a[1]; q.push(1);
	while(!q.empty())
	{
		int i=q.front(); q.pop();
		in[i]=0;
		for(int p=last[i];p;p=E[p].pre)
		{
			int j=E[p].to;
			if(MIN[j]==INF||MIN[j]>MIN[i])
			{
				MIN[j]=min(a[j],MIN[i]);
				if(!in[j])
				{
					in[j]=1;
					q.push(j);
				}
			}
		}
	}
}

void spfa2()
{
	queue<int>q;
	memset(in,0,sizeof(in));
	for(int i=1;i<=N;i++)
        MAX[i]=-1;
	MAX[N]=a[N];
	q.push(N);
	while(!q.empty())
	{
		int i=q.front(); q.pop(); in[i]=0;
		for(int p=last2[i];p;p=G1[p].pre)
		{
			int j=G1[p].to;
			if(MAX[j]==-1||MAX[j]<MAX[i])
			{
				MAX[j]=max(a[j],MAX[i]);
				if(!in[j])
				{
					in[j]=1;
					q.push(j);
				}
			}
		}
	}
}

int main()
{
	int i,u,v,op;
	read(N);
	read(M);
	for(i=1;i<=N;i++)
        read(a[i]);
	for(i=1;i<=M;i++)
	{
		read(u);
		read(v);
		read(op);
		if(op==2)
            addedge(v,u),addedgG1(u,v);
		addedge(u,v);addedgG1(v,u);
	}
	spfa1();
	spfa2();
	int ans=0;
	for(i=1;i<=N;i++)
        ans=max(ans,MAX[i]-MIN[i]);
	printf("%d",ans);
}

 

发布了50 篇原创文章 · 获赞 53 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章