洛谷 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;
}


posted @ 2021-08-04 16:07  panjx  阅读(47)  评论(0编辑  收藏  举报