题目链接:P1073 最优贸易
题目大意
在一号城市开始走,一直走到n号城市,可以在路径上买东西和卖东西,使其赚的钱最大, 也可以不买不卖
solution
第一眼题目 (Tarjan) 缩点?写起来是不是有点长啊
那我们呢就用分层图做吧,然后跑一个 (SPFA) (不是死了么/微笑)
每一层的连边都为 (0) ,然后第一层想第二层连边代表买入为负的,第二层向第三层连边代表卖出,然后在与超级终点连边,总此三层,然后跑最长路
code:
/**
* Author: Alieme
* Data: 2020.8.30
* Problem: P1073
* Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#define ll long long
#define rr register
#define inf 1e9
#define MAXN 100010
using namespace std;
inline int read() {
int s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
struct Node {
int v;
int len;
Node() {}
Node(int V, int Len) {v = V, len = Len;}
};
int n, m;
int v[MAXN], d[MAXN << 2];
vector<Node> G[MAXN << 2];
void add(int x, int y) {
G[x].push_back(Node(y, 0));
G[x + n].push_back(Node(y + n, 0));
G[x + 2 * n].push_back(Node(y + 2 * n, 0));
G[x].push_back(Node(y + n, -v[x]));
G[x + n].push_back(Node(y + 2 * n, v[x]));
}
queue<int> q;
bool inq[MAXN << 2];
void SPFA() {
for (rr int i = 1; i <= n; i++) d[i] = -inf;
d[1] = 0;
inq[1] = true;
q.push(1);
while (!q.empty()) {
int tp = q.front();
q.pop();
inq[tp] = false;
int len = G[tp].size();
for (rr int i = 0; i < len; i++) {
Node x = G[tp][i];
if (d[x.v] < d[tp] + x.len) {
d[x.v] = d[tp] + x.len;
if (inq[x.v] == false) {
q.push(x.v);
inq[x.v] = true;
}
}
}
}
}
signed main() {
n = read();
m = read();
for (rr int i = 1; i <= n; i++) v[i] = read();
for (rr int i = 1; i <= m; i++) {
int x = read();
int y = read();
add(x, y);
int z = read();
if (z == 2) add(y, x);
}
G[n].push_back(Node(3 * n + 1, 0));
G[n * 3].push_back(Node(3 * n + 1, 0));
n = 3 * n + 1;
SPFA();
cout << d[n];
}