洛谷P1073 最优贸易

反向建图+dijkstra

切一道老题水水。。。

题目的意思是让我们找到两个点x,y,使得差值最大。

所以我们先在正向图跑dijkstra,用d数组表示从起点到i点的最少价值,所以可以用d[i]=min(w[i], d[j])更新d值

再用f数组表示从该点到终点的最大价值,这次我们在反向图从n点开始跑dijkstra,这在反向图表示从n到某点的最短路(在正向图即该点到终点的最短路),更新方法与上述类似。
最后遍历每个点去f[i]-d[i]的最大值即可。

我开始想用f/d直接更新,d[i]=min(d[i], d[j])。。但是这样有时候得不到正确答案,因为我太弱了,只能想到当图不联通的时候这样是错误的。。。

因为当某个点与起点或者终点不联通时,按照d[i]=min(d[i], d[j])的方法更新,需要一开始就给所有点的d/f数组附上w的初值,这样以来就变成了d[i]=f[i],最后得出的答案一定是0,但是其实我们在联通的那一部分已经有卖出差价了

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
    int X = 0, w = 0; char ch = 0;
    while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C yql){
    A ans = 1;
    for(; p; p >>= 1, x = 1LL * x * x % yql)if(p & 1)ans = 1LL * x * ans % yql;
    return ans;
}
const int N = 100000;
int n, m, cnt1, cnt2, head1[N], head2[N], w[N], d[N], f[N];
bool vis[N];
struct Edge{
    int v, next;
}edge1[5*N], edge2[5*N];

void addEdge1(int a, int b){
    edge1[cnt1].v = b;
    edge1[cnt1].next = head1[a];
    head1[a] = cnt1 ++;
}

void addEdge2(int a, int b){
    edge2[cnt2].v = b;
    edge2[cnt2].next = head2[a];
    head2[a] = cnt2 ++;
}

void dijkstra_to(){
    memset(d, INF, sizeof d);
    memset(vis, 0, sizeof vis);
    //for(int i = 1; i <= n; i ++) d[i] = w[i];
    priority_queue<pair<int, int>, vector<pair<int, int>>, less<pair<int, int>>> pq;
    d[1] = w[1];
    pq.push(make_pair(d[1], 1));
    while(!pq.empty()){
        int s = pq.top().second, dis = pq.top().first; pq.pop();
        if(vis[s]) continue;
        vis[s] = true;
        for(int i = head1[s]; i != -1; i = edge1[i].next){
            int u = edge1[i].v;
            d[u] = min(dis, w[u]);
            pq.push(make_pair(d[u], u));
        }
    }
}

void dijkstra_from(){
    memset(f, 0, sizeof f);
    memset(vis, 0, sizeof vis);
    //for(int i = 1; i <= n; i ++) f[i] = w[i];
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    f[n] = w[n];
    pq.push(make_pair(w[n], n));
    while(!pq.empty()){
        int s = pq.top().second, dis = pq.top().first; pq.pop();
        if(vis[s]) continue;
        vis[s] = true;
        for(int i = head2[s]; i != -1; i = edge2[i].next){
            int u = edge2[i].v;
            f[u] = max(dis, w[u]);
            pq.push(make_pair(f[u], u));
        }
    }
}

int main(){

    memset(head1, -1, sizeof head1);
    memset(head2, -1, sizeof head2);
    n = read(), m = read();
    for(int i = 1; i <= n; i ++) w[i] = read();
    for(int i = 0; i < m; i ++){
        int a = read(), b = read(), c = read();
        if(c == 1) addEdge1(a, b), addEdge2(b, a);
        else if(c == 2) addEdge1(a, b), addEdge1(b, a), addEdge2(a, b), addEdge2(b, a);
    }
    dijkstra_to(), dijkstra_from();
    int ans = 0;
    for(int i = 1; i <= n; i ++)
        ans = max(ans, f[i] - d[i]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2019-03-12 19:13  清楚少女ひなこ  阅读(115)  评论(0编辑  收藏  举报