• 洛谷 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;
    }
    
    
    
  • 相关阅读:
    Log4Net 自定义级别,分别记录到不同的文件中
    带着忧伤,寻觅快乐
    程序员进阶学习书籍
    PHP编码技巧
    PHP精度问题
    Laravel5 构造器高级查询条件写法
    正则表达式 /i /g /m /ig /gi
    MySQL运算符的优先级
    PHP获取当前页面完整路径URL
    使用ssl模块配置同时支持http和https并存
  • 原文地址:https://www.cnblogs.com/pjxpjx/p/15099379.html
Copyright © 2020-2023  润新知