P1073 [NOIP 2009 提高组] 最优贸易

链接

https://www.luogu.com.cn/problem/P1073

思路

刚开始的思路是tarjan:缩点,统计每个强联通分量的min和max。然后再根据有向图去求答案。但是这样太过于繁琐,所以采用分层图的办法。这篇题解讲的已经够详细了:https://www.luogu.com.cn/article/7h7adii9。但是代码重新搓了个,用的是链式前向星。注意这里的边卡了,改成1e6才行。

代码

#define _CRT_SECURE_NO_WARNINGS 0
#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
using namespace std;

const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int INF = LLONG_MIN;
int n, m;
int head[N * 3];
int cnt;
struct edge
{
	int to, w, next;
}e[M * 3];
void init()
{
	for (int i = 0; i < N * 3; i++)head[i] = -1;
	for (int i = 0; i < M * 3; i++)e[i].next = -1;
	cnt = 0;
	return;
}
void addedge(int u, int v, int val)
{
	e[cnt].to = v;
	e[cnt].w = val;
	e[cnt].next = head[u];
	head[u] = cnt++;
}

int cal(int i, int num)
{
	//i号节点第num层
	return i + num * n;
}

int dis[N * 3];
bool inq[N * 3];

int spfa(int s)
{
	memset(inq, 0, sizeof(inq));
	for (int i = 1; i < N * 3; i++)
	{
		dis[i] = INF;
	}
	dis[s] = 0;
	queue<int>q;
	q.push(s);
	inq[s] = true;
	while (!q.empty())
	{
		int now = q.front();
		q.pop();
		inq[now] = false;
		for (int i = head[now]; i != -1; i = e[i].next)
		{
			int v = e[i].to;
			int w = e[i].w;
			if (dis[now] + w > dis[v])
			{
				dis[v] = dis[now] + w;
				if (!inq[v])
				{
					q.push(v);
					inq[v] = true;

				}
			}


		}
	}
	return 0;
}



signed main()
{
	IOS;
	init();
	cin >> n >> m;
	for (int i = 1, x; i <= n; i++)
	{
		cin >> x;
		addedge(cal(i, 0), cal(i, 1), 0 - x);
		addedge(cal(i, 1), cal(i, 2), x);
	}
	for (int i = 1; i <= m; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		for (int ct = 0; ct <= 2; ct++)
		{
			addedge(cal(u, ct), cal(v, ct), 0);
			if (w == 2)addedge(cal(v, ct), cal(u, ct), 0);
		}
	}
	spfa(cal(1, 0));
	cout << dis[cal(n, 2)];
	return 0;
}


posted @ 2025-02-19 17:05  WHUStar  阅读(41)  评论(0)    收藏  举报