目录

一、提问词

二、IMA+DeepSeek回复

1、题目描述

2、解题思路

3、实现代码

4、代码说明

三、 说明


一、提问词

你是一个具有10年以培训经验的信息奥赛教练,现请你撰写NOIP2009提高组T3最优贸易题解:
一、题解至少包括以下几个部分:
'''
1、题目描述
2、解题思路
3、实现代码
4、代码说明
'''
二、要求
'''
1、代码符合C++98规范
2、从文件“trade.in”读数据,答案写入文件“trade.out”。
'''

二、IMA+DeepSeek回复

1、题目描述

C国有n个城市和m条道路,每条道路连接两个城市,可能是单向或双向。阿龙想选择一个城市买入水晶球,并在之后某个城市卖出,最多进行一次交易。求最大可能的差价。

输入格式:
第1行:n、m(城市数和道路数)
第2行:n个整数表示各城市水晶球价格
接下来m行:x,y,z描述道路(z=1为单向,z=2为双向)

输出格式:
一个整数表示最大收益(若无交易则输出0)

2、解题思路

三步处理法

  1. 正向SPFA求最小价:从起点出发,计算每个城市可达路径的最小价格
  2. 反向SPFA求最大价:从终点出发反向建图,计算各城市可达终点的路径的最大价格
  3. 枚举求差值:遍历所有城市,计算max(当前最大卖出价 - 历史最小买入价)

方法正确性证明:任何合法路径都可以划分为1→k→n,其中k为买卖分界点。正向处理保证买入最低价,反向处理保证卖出最高价。1

3、实现代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100005;

struct Edge{
    int to,next;
}e[maxn*10],re[maxn*10];  //正向边和反向边

int head[maxn],rhead[maxn];  //正向图和反向图头指针
int price[maxn],min_cost[maxn],max_value[maxn];
bool inq[maxn],vis[maxn];
int n,m,cnte;

void add_edge(int u,int v){
    //正向图邻接表
    e[++cnte].to = v;
    e[cnte].next = head[u];
    head[u] = cnte;
    
    //反向图邻接表
    re[cnte].to = u;
    re[cnte].next = rhead[v];
    rhead[v] = cnte;
}

void forward_spfa(){
    memset(min_cost,0x3f,sizeof min_cost);
    queue<int> q;
    q.push(1);
    min_cost[1] = price[1];
    inq[1] = true;

    while(!q.empty()){
        int u = q.front(); q.pop();
        inq[u] = false;
        for(int p=head[u];p;p=e[p].next){
            int v = e[p].to;
            int new_min = min(min_cost[u], price[v]);
            if(min_cost[v] > new_min){
                min_cost[v] = new_min;
                if(!inq[v]){
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
    }
}

void reverse_spfa(){
    memset(max_value,-0x3f,sizeof max_value);
    queue<int> q;
    q.push(n);
    max_value[n] = price[n];
    inq[n] = true;

    while(!q.empty()){
        int u = q.front(); q.pop();
        inq[u] = false;
        for(int p=rhead[u];p;p=re[p].next){
            int v = re[p].to;
            int new_max = max(max_value[u], price[v]);
            if(max_value[v] < new_max){
                max_value[v] = new_max;
                if(!inq[v]){
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
    }
}

int main(){
    freopen("trade.in","r",stdin);
    freopen("trade.out","w",stdout);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&price[i]);
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add_edge(x,y);
        if(z == 2) add_edge(y,x);
    }

    forward_spfa();
    reverse_spfa();

    int ans = 0;
    for(int i=1;i<=n;i++)
        ans = max(ans, max_value[i]-min_cost[i]);
    printf("%d\n",ans);
    return 0;
}

 

4、代码说明

  1. 数据结构

    • 使用两个邻接表存储正向图和反向图
    • min_cost[]数组记录从起点到各城市路径中最小的买入价
    • max_value[]数组记录从该城市到终点路径中最大的卖出价
  2. 关键过程

    • add_edge:同时维护正向和反向邻接表,处理双向边时添加反向边
    • forward_spfa:使用改进SPFA算法逐步松弛得到每个节点的最小价格
    • reverse_spfa:在反向图上进行SPFA得到每个节点的最大可卖出价格
  3. 复杂度分析

    • 时间复杂度:O(M),两个SPFA的时间复杂度均为线性
    • 空间复杂度:O(N+M),存储正向和反向图的边
  4. 算法优势

    • 避免暴力枚举所有路径
    • 保证处理包含环路的复杂图结构
    • 反向预处理确保卖出点可达终点

本解法可稳定处理1e5级别的数据规模,符合题目要求。

三、 说明

1、本次题解用了3次才得到当前结果,第一次仅分析过程结束,没有最终结论。第二次生成的结果由于没有提“符合C++98规范”这个要求,生成的代码在【Cena】中不能编译(没有在NoiLinux环境中测试,估计此环境应该能够AC)。第三次修改提问词为文章所述才得到文章呈现的结论。

2、题解中的代码经过【Cena】测试通过。

3、本文的【摘要】也是由IMA+DeepSeek生成后加工而成,提问词是:“请继续为上面题解提取不超过100字的摘要”。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐