ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【NOIP2009】最优贸易

2020-01-29 13:00:16  阅读:309  来源: 互联网

标签:CH int NOIP2009 vis num qi 贸易 最优 pi


题目链接:https://www.luogu.com.cn/problem/P1073

题目大意:给定一张有向图 , 其中每个点有一个权值 \(w\), 求出 \(1\) 到 \(n\) 的所有路径中 \(w_i - w_j\) ( \(i\) , \(j\) 为同一条路径上的两个节点 , 且 \(i\) 比 \(j\) 后遍历到 )​ 的最大值

solution

算法一:

设从 1 到 \(i\) 所有路径上节点权值的最大值为 \(g_i\) , \(i\) 到 \(n\) 所有路径上节点权值的最小值为 \(f_i\) , 可以用SPFA分别求出这两个值 , 再遍历每个节点 , 求得 \(max\left\{g_i - f_i\right\}(i \leq n)\)即为答案

code

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
const int N = 1e6 + 10;
int n, m, now, fst[N], nxt[N], num[N], wi[N], ans;
int ni, ft[N], nt[N], nm[N];
void add(int u, int v, int k) {
    nxt[++now] = fst[u], fst[u] = now, num[now] = v;
    nt[++ni] = ft[v], ft[v] = ni, nm[ni] = u;
    if(k) {
        nxt[++now] = fst[v], fst[v] = now, num[now] = u;
        nt[++ni] = ft[u], ft[u] = ni, nm[ni] = v;
    }
}
int vis[N], ma[N], mi[N];
void Spfa_max() {
    queue<int> qi;
    qi.push(n); vis[n] = true; ma[n] = wi[n];
    while(!qi.empty()) {
        int pi = qi.front(); qi.pop(); vis[pi] = false;
        for(int i = ft[pi]; i; i = nt[i]) 
            if(max(ma[pi], wi[nm[i]]) > ma[nm[i]]) {
                ma[nm[i]] = max(ma[pi], wi[nm[i]]);
                if(!vis[nm[i]]) qi.push(nm[i]), vis[nm[i]] = true;
            }
    }
}
void Spfa_min() {
    queue<int> qi;
    memset(vis, 0, sizeof(vis));
    memset(mi, 0x3f, sizeof(mi));
    qi.push(1); vis[1] = true; mi[1] = wi[1];
    while(!qi.empty()) {
        int pi = qi.front(); qi.pop(); vis[pi] = false;
        for(int i = fst[pi]; i; i = nxt[i])
            if(min(mi[pi], wi[num[i]]) < mi[num[i]]) {
                mi[num[i]] = min(mi[pi], wi[num[i]]);
                if(!vis[num[i]]) qi.push(num[i]), vis[num[i]] = true;
            }
    }
}
int main() {
    //file("");
    int u, v, k;
    read(n), read(m);
    for(int i = 1; i <= n; i++) read(wi[i]);
    for(int i = 1; i <= m; i++)
        read(u), read(v), read(k), add(u, v, k - 1);
    Spfa_max(), Spfa_min();
    for(int i = 1; i <= n; i++)
        ans = max(ans, ma[i] - mi[i]);
    cout << ans << endl;
    return 0;
}

算法二:

建三张一模一样的分层图 , 其中每个分层图内路径长度为 0 , 相邻两张分层图中从 \(i\) 到 \(i\) 连边 , 其中一号图与二号图间 \(i\) 号节点连边的长度设为 \(-w_i\) , 意为从 \(i\) 号节点买进 , 二号图与三号图间 \(i\) 号节点连边的长度设为 \(w_i\) 意为从 \(i\) 号节点卖出 , 这样从一号图中的 1号节点到三号图中 \(n\) 号节点的最长路即为答案 , 可用SPFA求出

code

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
const int N = 3e6 + 10;
int n, m, now, fst[N], nxt[N], num[N], wi[N], vi[N];
void add(int u, int v, int w) {
    nxt[++now] = fst[u], fst[u] = now, num[now] = v, wi[now] = w;
}
void Add_edge(int u, int v, int k) {
    add(u, v, 0), add(n + u, n + v, 0), add(n * 2 + u, n * 2 + v, 0);
    if(k == 2) add(v, u, 0), add(n + v, n + u, 0), add(n * 2 + v, n * 2 + u, 0);
}
int vis[N], lt[N];
void Spfa() {
    memset(lt, 0x80, sizeof(lt));
    queue<int> qi; qi.push(1); vis[1] = true, lt[1] = 0;
    while(!qi.empty()) {
        int pi = qi.front(); qi.pop(); vis[pi] = false;
        for(int i = fst[pi]; i; i = nxt[i])
            if(lt[pi] + wi[i] > lt[num[i]]) {
                lt[num[i]] = lt[pi] + wi[i];
                if(!vis[num[i]]) qi.push(num[i]), vis[num[i]] = true;
            }
    }
}
int main() {
    //file("");
    int u, v, k;
    read(n), read(m);
    for(int i = 1; i <= n; i++) read(vi[i]);
    for(int i = 1; i <= m; i++)
        read(u), read(v), read(k), Add_edge(u, v, k);
    for(int i = 1; i <= n; i++) add(i, i + n, -vi[i]), add(n + i, n * 2 + i, vi[i]);
    n = n * 3; Spfa();
    cout << max(lt[n], 0) << endl;
    return 0;
}

标签:CH,int,NOIP2009,vis,num,qi,贸易,最优,pi
来源: https://www.cnblogs.com/magicduck/p/12240063.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有