P1073 最优贸易

本文介绍了一种解决有费用路径问题的最优贸易路径算法,通过构建三层分层图(起点层、购买层、出售层),利用Dijkstra算法结合最小堆或最大堆优化,找到从起点到终点的最低成本路径。文章详细解释了算法原理,并提供了具体实现代码。

[最优贸易]

  • 有费用的路径问题可以考虑最短路
  • 分为三个阶段,起点到购买点,购买点到售卖点,售卖点到终点
  • 使用分层图思想,将原图复制为三份应对三个阶段
  • 从第一层图到第二层图对应购买,对于每个点从第一层到第二层连边,权值为在这个点购买的费用
  • 从第二层图到第三层图对应售卖,同理连边,权值为负的费用
  • 由于移动不需要费用,三层图内部的边权为0
  • 之后求出来的最短路,层内部的对应移动,跨层的对应购买或者销售操作

  • 建三层图(核心思想)
  • 起点层
  • 购买层
  • 出售层
  • 也就是说有3n个点,我们立3n+1点为最终点,当然通向它的权值是零,与它相连的是n(不买卖直接走)和3n(卖卖后)
    10006.png

  • 方法一:Dijkstra + 最小堆优化
  • 立起点层到购买层权值为正数
  • 立购买层到出售层权值为负数
  • 意为总共付出的费用(付出负数即为赚钱)
  • 方法二:Dijkstra + 最大堆优化
  • 立起点层到购买层权值为负数
  • 立购买层到出售层权值为正数
  • 意为总共得到的费用

  • 最终答案在dist[3 * n + 1]
  • 法一输出abs(dist[3 * n + 1])
  • 法二输出dist[3 * n + 1]

Dijkstra + 最小堆 代码
#include <bits/stdc++.h>

#define pr pair<int, int>
#define mk make_pair

using namespace std;

const int N = 3e5 + 1;

struct Edge{
    int v,w,nxt;
}edge[N << 2];

int n,m,top;
int cost[N],head[N],dist[N]; 

void addedge(int u, int v, int w){
    edge[++top].v = v;
    edge[top].w = w;
    edge[top].nxt = head[u];
    head[u] = top;
}

void add(int x, int y){
    addedge(x, y, 0), addedge(n + x, n + y, 0), addedge(2 * n + x, 2 * n + y, 0);
    addedge(x, n + y, cost[y]), addedge(n + x, 2 * n + y, -cost[y]);
}

priority_queue<pr, vector<pr>, greater<pr> > q; 
void Dijkstra(){
    for(int i = 1; i <= n; ++i) dist[i] = dist[n + i] = dist[2 * n + i] = 1e9;
    dist[1] = 0;
    q.push(mk(dist[1], 1)); 
    while(!q.empty()){
        int u = q.top().second;
        int d = q.top().first; q.pop();
        if(d > dist[u]) continue;
        for(int i = head[u]; i; i = edge[i].nxt){
            int v = edge[i].v;
            int w = edge[i].w;
            if(dist[u] + w < dist[v]) dist[v] = dist[u] + w, q.push(mk(dist[v], v));
        }
    }
    cout << abs(dist[3 * n + 1]);
}

int main(){
    cin >> n >> m;
    for(int i = 1, x; i <= n; ++i)
        cin >> x, 
            cost[i] = cost[n + i] = cost[2 * n + i] = x;
    for(int i = 1, x, y, z; i <= m; ++i){
        cin >> x >> y >> z;
        add(x, y);  
        if(z == 2) add(y, x);
    }
    addedge(n, 3 * n + 1, 0); //不买卖,直接走 
    addedge(3 * n, 3 * n + 1, 0); //终点是3 * n + 1 
    Dijkstra();
    return 0;   
}

转载于:https://www.cnblogs.com/Adventurer-H/p/11281701.html

下载前必看:https://pan.quark.cn/s/a4b39357ea24 在本资料中,将阐述如何运用JavaScript达成单击下拉列表框选定选项后即时转向对应页面的功能。 此种技术适用于网页布局中用户需迅速选取并转向不同页面的情形,诸如网站导航栏或内容目录等场景。 达成此功能,能够显著改善用户交互体验,精简用户的操作流程。 我们须熟悉HTML里的`<select>`组件,该组件用于构建一个选择列表。 用户可从中选定一项,并可引发一个事件来响应用户的这一选择动作。 在本次实例中,我们借助`onchange`事件监听器来实现当用户在下拉列表框中选定某个选项时,页面能自动转向该选项关联的链接地址。 JavaScript里的`window.location`属性旨在获取或设定浏览器当前载入页面的网址,通过变更该属性的值,能够实现页面的转向。 在本次实例的实现方案里,运用了`eval()`函数来动态执行字符串表达式,这在现代的JavaScript开发实践中通常不被推荐使用,因为它可能诱发安全问题及难以排错的错误。 然而,为了本例的简化展示,我们暂时搁置这一问题,因为在更复杂的实际应用中,可选用其他方法,例如ES6中的模板字符串或其他函数来安全地构建和执行字符串。 具体到本例的代码实现,`MM_jumpMenu`函数负责处理转向逻辑。 它接收三个参数:`targ`、`selObj`和`restore`。 其中`targ`代表要转向的页面,`selObj`是触发事件的下拉列表框对象,`restore`是标志位,用以指示是否需在转向后将下拉列表框的选项恢复至默认的提示项。 函数的实现通过获取`selObj`中当前选定的`selectedIndex`对应的`value`属性值,并将其赋予`...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值