LuoGu P1073 最优贸易【双向SPFA|思维】

题目链接

很有意思的一道题,首先我们要明确题目要求的是什么东西,因为贸易最多进行一次,那么实际上是让我们找到一个点 v v v,在起点到这个点的路径上以一个价格 m i n p [ v ] minp[v] minp[v]买入,然后在该点到终点的路径上以价格 m a x p [ v ] maxp[v] maxp[v]的价格卖出,使得 m a x p [ v ] − m i n p [ v ] maxp[v]-minp[v] maxp[v]minp[v]全局最大,如何实现这个功能呢?

  • 求从起点开始到某个点的最低买入价格:直接上spfa,
if (min(minp[u], arr[v]) < minp[v]) {//minp[u]:起点到u的最低买入价格, arr[v]:v的买入价格
	minp[v] = min(minp[u], arr[v]);//u->v 更新v的买入价格
	if (!vis[v]) {
		q.push(v); vis[v] = 1;//入队并标记
	}
}
  • 求所有点到终点的最高卖出价格:这类其他点到某点的最短距离/最低价格/最大花费一类的问题,都可以经过反向建图修改为单点到其他点的***问题。建好图之后,我们和上面一样来一个spfa即可
if (max(maxp[u], arr[v]) > maxp[v]) {//maxp[v]:v到终点的最高卖出价格
	maxp[v] = max(maxp[u], arr[v]);
	if (!vis[v]) {
		q.push(v); vis[v] = 1;
	}
}
#define inf 0x3f3f3f3f
#define ll long long
#define vec vector
#define P pair
#define MAX 100005

vec G[MAX];
int n, m, z[MAX * 5], a[MAX * 5], b[MAX * 5], arr[MAX];
int minp[MAX], maxp[MAX], vis[MAX];

void spfa(int s, int k) {
	memset(vis, 0, sizeof(vis));
	queue<int> q; q.push(s); vis[s] = 1;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for (int i = 0; i < G[u].size(); i++) {
			int v = G[u][i];
			if (k == 1) {//从1号位置求每个城的最低买入价格
				if (min(minp[u], arr[v]) < minp[v]) {
					minp[v] = min(minp[u], arr[v]);
					if (!vis[v]) {
						q.push(v); vis[v] = 1;
					}
				}
			}
			else {//从n号位置求到每个城的最高卖出价格
				if (max(maxp[u], arr[v]) > maxp[v]) {
					maxp[v] = max(maxp[u], arr[v]);
					if (!vis[v]) {
						q.push(v); vis[v] = 1;
					}
				}
			}
		}
	}
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> arr[i];
	for (int i = 0; i < m; i++) {
		cin >> a[i] >> b[i] >> z[i];
		G[a[i]].push_back(b[i]);
		if (z[i] == 2)G[b[i]].push_back(a[i]);
	}

	for (int i = 1; i <= n; i++) 
		minp[i] = inf, maxp[i] = 0;
	
	//从1号城到其他城买入的最低价格
	minp[1] = arr[1]; spfa(1, 1);
	//反向建图
	for (int i = 1; i <= n; i++)G[i].clear();
	for (int i = 0; i < m; i++) {
		G[b[i]].push_back(a[i]);
		if (z[i] == 2)G[a[i]].push_back(b[i]);
	}
	//从其他城到n号城卖出的最高价格
	maxp[n] = arr[n]; spfa(n, 2);

	int res = 0;
	for (int i = 1; i <= n; i++)
		res = max(maxp[i] - minp[i], res);
	cout << res << endl;
}

你可能感兴趣的:(牛客网&LuoGu练习题)