最优贸易 最短路 图论

2 篇文章 0 订阅
1 篇文章 0 订阅

最优贸易

最优贸易

这个题不会做肯定就是因为你想得太麻烦了.

简单来说每一个城市有指定的价格,那么最大的限制就是哪些点之间可以相互流通的问题了.

我们这样思考:

  1. 我要知道每一个节点能够拿到来自其他的城市的最低的买入的价格是多少.怎么做呢? 想象我们用bfs做广度增广,每一次增广我们都拿着当前节点的可以得到的最低的买入价格去增广,如果下一个点的买入价格可以更低,那么很明显,下一个节点的买入价格在记录的时候肯定不能把当前更新给它,就是要保留目标节点的买入价格作为目标节点增广的买入价格.比如: 我们已知从1号节点出发,那么就记录1号节点的买入价格,再去找其他可以到达的节点,更新到达这个节点为止的最低的买入价格,如果可以到达目标点3,3点的买入价格更低,那么3就不管1的买入价格,下次3增广时候就以3的买入价格增广. 如果目标点2的买入价格比3高,那么我们把2的买入价格更新为1的买入价格,相当于我们可以从1号买来一个珍珠,这个珍珠可以到达2号节点,那么2号结点再次增广时相当于用这个珍珠去增广后面的点.

  2. 个人的考虑是我需要知道有哪些节点可以到达最终的点,这个是要记录的,因为如果交易的地点发生在某一些地方正好回不到终点,那么这个点是不能作为交易地点的.为了知道哪些点能够到达终点,所以我的做法是特地造了一个返图,不知道这种做法是不是合理(如果有更好的策略可以告诉我)

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
const int maxm = 1e6 + 30;
const int maxn = 1e6 + 10;
struct edge
{
    ll s, d, next;
};
edge es[maxm];
ll head[maxn];
ll savecnt = 0;
inline void adde(ll s, ll d)
{
    edge& nowe = es[savecnt];
    nowe.s = s;
    nowe.d = d;
    nowe.next = head[s];
    head[s] = savecnt++;
}
int N, M;
edge es1[maxm];
ll head1[maxn];
ll savecnt1 = 0;
inline void adde1(ll s, ll d)
{
    edge& nowe = es1[savecnt1];
    nowe.s = s;
    nowe.d = d;
    nowe.next = head1[s];
    head1[s] = savecnt1++;
}
struct node {
    int id;
    int val;
    bool operator<(const node& n)const {
        return val > n.val;
    }
};
int savereal[maxn];
int saveori[maxn];
#define min(i ,j) (i<j?i:j)

void bfs(int s) {
    priority_queue<node> q;
    q.push(node{ 1, saveori[1] });

    while (!q.empty()) {
        node nownode = q.top();
        q.pop();
        if (savereal[nownode.id] != nownode.val)
            continue;

        for (int eid = head[nownode.id]; eid != -1; eid = es[eid].next) {
            edge& nowe = es[eid];
            //更新成功,放进队列
            if (savereal[nowe.d] > min(nownode.val, saveori[nowe.d])) {
                savereal[nowe.d] = min(nownode.val, saveori[nowe.d]);
                q.push({ nowe.d, savereal[nowe.d] });
            }
        }
    }
}
int visN[maxn];
int vis1[maxn];
void bfs2(int s, int* vis, int* nowhead, edge* nowes) {
    queue<int> q;
    vis[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int nowid = q.front();
        q.pop();
        for (int eid = nowhead[nowid]; eid != -1; eid = nowes[eid].next) {
            edge& nowe = nowes[eid];
            if (!vis[nowe.d]) {
                q.push(nowe.d);
                vis[nowe.d] = 1;
            }
        }
    }
}
int main()
{
    // freopen("in.txt", "r", stdin);
    memset(savereal, 0x3f, sizeof(savereal));
    memset(head, -1, sizeof(head));
    memset(head1, -1, sizeof(head1));
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        scanf("%d", &saveori[i]);
    }
    savereal[1] = saveori[1];
    for (int i = 1; i <= M; i++) {
        int s, d, z;
        scanf("%d %d %d", &s, &d, &z);
        adde(s, d);
        adde1(d, s);
        if (z == 2) {
            adde(d, s);
            adde1(s, d);
        }
    }
    //这个 bfs为了统计哪些点能够到达 终点N
    bfs2(N, visN, head1, es1);
    //这个 bfs为了统计哪些点能够从1出发到达
    bfs2(1, vis1, head, es);
    //这个 bfs就是为了珍珠的价格增广
    bfs(1);
    int ans = -1;
    for (int i = 1; i <= N; i++) {
        //如果一个点既能够被起点访问到,也能够被到达终点,那么这个点就能够作为交易的发生地
        if (vis1[i] && visN[i]) {
            ans = max(saveori[i] - savereal[i], ans);
        }
    }
    cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值