洛谷 P1073/AcWing 341 [NOIP2009 提高组] 最优贸易
Description
AcWing
洛谷
Solution
Solution 1 \(50pts\)
因为50分的数据保证了图是一个DAG,所以可以直接拓扑。
Solution 2 \(100pts\)
每次肯定是先买后卖,可以枚举这个买卖的分界点。设分界点为k,则买一定在1->k的路上(包括1与k),卖一定在k->n的路上(包括k与n)。
因为要求赚到的差价最大,所以买时一定价格越低越好,卖时一定价格越高越好。
-
设 \(dismin[i]\) 表示从 \(1\) 到 \(i\) 的路上点的最小值;
-
设 \(dismax[i]\) 表示从 \(i\) 到 \(n\) 的路上点的最大值。
最后答案即为 \(max\){\(dismax[i] - dismin[i]\)}\((1≤i≤n)\)。
dismin[i] 与 dismax[i] 都可以通过最短路SPFA算法给求出来,但不能使用dijkstra。
对于dismax[i],可以建一个反图,在这个反图上跑从n点到其他点SPFA。
样例例子:
原图: 反图:
关于为什么不能使用 \(dijkstra\) 求解本题:
由于这题数据过大,如果用 \(dijkstra\) 算法必须要堆优化,而堆优化的前提是每个点只能进堆一次,很明显,这题并不是单纯地把权值累加,是求最大/最小值,所以一个点可能会进多次,与前提矛盾,只能使用 \(SPFA\) 。
Code:
// by pjx Aug.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#define REP(i, x, y) for(register int i = x; i < y; i++)
#define rep(i, x, y) for(register int i = x; i <= y; i++)
#define PER(i, x, y) for(register int i = x; i > y; i--)
#define per(i, x, y) for(register int i = x; i >= y; i--)
#define lc (k << 1)
#define rc (k << 1 | 1)
using namespace std;
const int N = 1E5 + 5;
int n, m;
int pri[N];
int dismax[N], dismin[N];
int b[N];
vector <int> g[N], rg[N];
queue <int> que;
void SPFA_min()//求出dismin数组的值
{
memset(dismin, 0x3f, sizeof dismin);//由于求最小值,需要初始化
dismin[1] = pri[1];
b[1] = 0;
que.push(1);
while(!que.empty())
{
int k = que.front();
que.pop();
b[k] = 0;
for(int j = 0; j < g[k].size(); j++)
{
int v = g[k][j];
int w = pri[v];
if(dismin[v] > min(dismin[k], w))//这里的更新判断有变化,是更新最小值
{
dismin[v] = min(dismin[k], w);
if(!b[v])
{
b[v] = 1;
que.push(v);
}
}
}
}
}
void SPFA_max()//求出dismax数组的值
{
dismax[n] = pri[n];//求最大值就不需要初始化~
b[n] = 0;
que.push(n);
while(!que.empty())
{
int k = que.front();
que.pop();
b[k] = 0;
for(int j = 0; j < rg[k].size(); j++)//在反图上跑SPFA
{
int v = rg[k][j];
int w = pri[v];
if(dismax[v] < max(dismax[k], w))//更新的是最大值
{
dismax[v] = max(dismax[k], w);
if(!b[v])
{
b[v] = 1;
que.push(v);
}
}
}
}
}
int main()
{
cin >> n >> m;
rep(i, 1, n)
{
cin >> pri[i];
}
rep(i, 1, m)
{
int x, y, opt;
cin >> x >> y >> opt;
if(opt == 1)
{
g[x].push_back(y);
rg[y].push_back(x);//rg是g的反图
}
else
{
g[x].push_back(y);
g[y].push_back(x);
rg[x].push_back(y);
rg[y].push_back(x);
}
}
SPFA_min();
SPFA_max();
int ans = -1;
rep(i, 1, n)
{
ans = max(ans, dismax[i] - dismin[i]);
}
cout << ans;
return 0;
}