【NOIP2009】最优贸易 trade

【问题描述】

    有n个城市和m条道路,道路有双向道路和单向道路。每个城市的水晶球价格不同,商人阿龙要从城市1走到城市n,城市和道路可以经过多次。阿龙可以在一个城市买入一个水晶球,然后在之后经过的城市卖出(最多交易一次)。求出阿龙最多能够获得的利润。

    1≤n≤100000,1≤m≤500000

【分析】

    最简单的想法是遍历全图,找到价格的Max和Min,相减得到答案。但是要保证必须先走到Min的城市,再走到Max的城市,所以这样是不行的。我们可以反向构图,分成正着走到n和倒着走到1,令Min[i] 表示从1开始正着走到i的城市中最小的价格,Max[i]表示从n倒着走到i的城市中最大的价格,则ans = max(Max[i] - Min[i])

    这样我们可以通过做两遍spfa或者bfs来得到Max和Min的值,规定时间内是可以通过的。

【代码】

    PS:我的代码比较戳,由于懒得写链表,直接用vector了,将就看吧。由于是用vector的,可能在某些机子上会计较慢一些,一般还是能过的。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int n,m;
int a[100001],Max[100001],Min[100001];
int q[1000001],h,t;
bool v[100001];
vector<int> edge[100001],edge1[100001];
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",&a[i]);
    for (int i = 1;i <= m;i ++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        edge[x].push_back(y);
        if (z > 1) edge[y].push_back(x);
        edge1[y].push_back(x);
        if (z > 1) edge1[x].push_back(y);
    }
    memset(Min,63,sizeof(Min));
    Min[1] = a[1];
    q[1] = 1;
    v[1] = true;
    h = 0,t = 1;
    while (h < t)
    {
        if (h != 0) v[q[h]] = false;
        h ++;
        for (int i = 0;i < edge[q[h]].size();i++)
            if (Min[edge[q[h]][i]] > min(a[edge[q[h]][i]],Min[q[h]]))
            {
                Min[edge[q[h]][i]] = min(a[edge[q[h]][i]],Min[q[h]]);
                if (!v[edge[q[h]][i]]) 
                {
                    q[++t] = edge[q[h]][i];
                    v[edge[q[h]][i]] = true;
                }
            }
    }
    memset(v,0,sizeof(v));
    Max[n] = a[n];
    q[1] = n;
    v[n] = true;
    h = 0,t = 1;
    while (h < t)
    {
        if (h != 0) v[q[h]] = false;
        h ++;
        for (int i = 0;i < edge1[q[h]].size();i++)
            if (Max[edge1[q[h]][i]] < max(a[edge1[q[h]][i]],Max[q[h]]))
            {
                Max[edge1[q[h]][i]] = max(a[edge1[q[h]][i]],Max[q[h]]);
                if (!v[edge1[q[h]][i]]) 
                {
                    q[++t] = edge1[q[h]][i];
                    v[edge1[q[h]][i]] = true;
                }
            }
    }
    int ans = 0;
    for (int i = 1;i <= n;i ++)
    {
        //printf("%d %d\n",Max[i],Min[i]);
        ans = max(ans,Max[i] - Min[i]);
    }
    cout << ans;
}

posted @ 2012-10-14 19:41  N_C_Derek  阅读(468)  评论(0编辑  收藏  举报