Miraclys

一言(ヒトコト)

洛谷P1073 最优贸易

\(\Large\textbf{Solution: } \large{1.分层图\\首先如果开两层,第一层到第二层表示买,第二层到第一层表示卖,会出现环或者卖卖多次的情况。\\所以开三层图,第一层表示没有买,二表示买,三表示卖。然后在图上跑最长路即可。注意到边权为负,所以要写Spfa。\\2.缩点+DP\\首先把图中的环缩成一个点,维护每个环的最大值与最小值,然后拓扑排序即可。我感觉这种做法细节较多,不太好写。}\)

\(\Large\textbf{Code: }\)

#include <bits/stdc++.h>
#define gc() getchar() 
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 1e5 + 5;
const int M = 5e5 + 5;
const int inf = 0x7fffffff;
int n, m, cnt, head[N * 3 + 100], a[N], vis[N * 3 + 100], dis[N * 3 + 100];

struct Edge {
	int to, next, val;	
}e[M * 10];
queue<int> q;

inline int read() {
	int x = 0;
	char ch = gc();
	while (!isdigit(ch)) ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	return x; 
}

inline void add(int x, int y, int w) {
	e[++cnt].to = y;
	e[cnt].val = w;
	e[cnt].next = head[x];
	head[x] = cnt;
}

inline void Spfa() {
	rep(i, 1, n * 3) dis[i] = -inf;
	dis[1] = 0; q.push(1); vis[1] = 1;
	while (!q.empty()) {
		int cur = q.front(); q.pop();
		vis[cur] = 0;
		for (int i = head[cur]; i ; i = e[i].next) {
			int u = e[i].to;
			if (dis[u] < dis[cur] + e[i].val) {
				dis[u] = dis[cur] + e[i].val;
				if (!vis[u]) q.push(u), vis[u] = 1;
			}
		}
	}
}

int main() {
	n = read(), m = read();
	rep(i, 1, n) a[i] = read();
	int x, y, ju;
	while (m--) {
		x = read(), y = read(), ju = read();
		add(x, y, 0); add(x + n, y + n, 0); add(x + 2 * n, y + 2 * n, 0); add(x, y + n, -a[x]); add(x + n, y + 2 * n, a[x]);
		if (ju == 2) {
			add(y, x, 0);
			add(y + n, x + n, 0);
			add(y, x + n, -a[y]);
			add(y + n, x + 2 * n, a[y]);
			add(y + 2 * n, x + 2 * n, 0);
		}
	}
	Spfa();
	printf("%d\n", max(dis[n], dis[3 * n]));
	return 0;
} 

\(\Large\textbf{Code: }\)

#include <bits/stdc++.h>
#define gc() getchar() 
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 1e5 + 5;
const int M = 5e5 + 5;
const int inf = 0x7fffffff;
int n, m, cnt, id, top, vis[N], head[N], s[N], a[N], dfn[N], low[N];
int tot, cot, ans[N], in[N], Min[N], bel[N], h[N], Max[N];

struct Edge {
	int to, next, fr;	
}e[M];

struct EDGE {
	int to, next;	
}E[M << 1];

inline int read() {
	int x = 0;
	char ch = gc();
	while (!isdigit(ch)) ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	return x; 
}

inline void add(int x, int y) {
	e[++cnt].fr = x;
	e[cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

inline void Tarjan(int x) {
	low[x] = dfn[x] = ++id;
	s[++top] = x; vis[x] = 1;
	for (int i = head[x]; i ; i = e[i].next) {
		int u = e[i].to;
		if (!dfn[u]) Tarjan(u), low[x] = min(low[x], low[u]);
		else if (vis[u]) low[x] = min(low[x], dfn[u]); 
	}
	if (dfn[x] == low[x]) {
		int y; ++tot;
		while (top) {
			y = s[top--];
			vis[y] = 0;
			bel[y] = tot;
			Max[tot] = max(Max[tot], a[y]);
			Min[tot] = min(Min[tot], a[y]);
			if (x == y) break;
		}
	}
}

inline void Add(int x, int y) {
	E[++cot].to = y;
	E[cot].next = h[x];
	h[x] = cot;
}

inline void DP() {
	queue<int> q;
	q.push(bel[1]);
	ans[bel[1]] = max(ans[bel[1]], Max[bel[1]] - Min[bel[1]]);
	while (!q.empty()) {
		int x = q.front(); q.pop();
		for (int i = h[x]; i ; i = E[i].next) {
			int u = E[i].to;
			--in[u];
			Min[u] = min(Min[u], Min[x]);
			ans[u] = max(ans[u], max(ans[x], Max[u] - Min[u]));
			if (!in[u]) q.push(u);
		}
	}
}

int main() {
	n = read(), m = read();
	rep(i, 1, n) a[i] = read();
	int x, y, ju;
	while (m--) {
		x = read(), y = read(), ju = read();
		add(x, y);
		if (ju == 2) add(y, x);
	}
	rep(i, 1, n) Min[i] = inf;
	rep(i, 1, n) if (!dfn[i]) Tarjan(i);
	rep(i, 1, cnt) {
		int u = bel[e[i].fr], v = bel[e[i].to];
		if (u != v) Add(u, v), ++in[v];
	}
	DP();
	printf("%d\n", ans[bel[n]]);
	return 0;
} 
posted @ 2020-03-25 07:35  Miraclys  阅读(94)  评论(0编辑  收藏  举报

关于本博客样式

部分创意和图片借鉴了

BNDong

的博客,在此感谢