NOIP2009 AcWing 341. 最優貿易(最短路)

題幹:

C國有 n 個大城市和 m 條道路,每條道路連接這 n 個城市中的某兩個城市。
任意兩個城市之間最多隻有一條道路直接相連。
這 m 條道路中有一部分爲單向通行的道路,一部分爲雙向通行的道路,雙向通行的道路在統計條數時也計爲1條。
C國幅員遼闊,各地的資源分佈情況各不相同,這就導致了同一種商品在不同城市的價格不一定相同。
但是,同一種商品在同一個城市的買入價和賣出價始終是相同的。
商人阿龍來到C國旅遊。
當他得知“同一種商品在不同城市的價格可能會不同”這一信息之後,便決定在旅遊的同時,利用商品在不同城市中的差價賺一點旅費。
設C國 n 個城市的標號從 1~n,阿龍決定從1號城市出發,並最終在 n 號城市結束自己的旅行。
在旅遊的過程中,任何城市可以被重複經過多次,但不要求經過所有 n 個城市
阿龍通過這樣的貿易方式賺取旅費:他會選擇一個經過的城市買入他最喜歡的商品——水晶球,並在之後經過的另一個城市賣出這個水晶球,用賺取的差價當做旅費。
因爲阿龍主要是來C國旅遊,他決定這個貿易只進行最多一次,當然,在賺不到差價的情況下他就無需進行貿易。
現在給出 n 個城市的水晶球價格,m 條道路的信息(每條道路所連接的兩個城市的編號以及該條道路的通行情況)。
請你告訴阿龍,他最多能賺取多少旅費。
輸入格式
第一行包含 2 個正整數 n 和 m,中間用一個空格隔開,分別表示城市的數目和道路的數目。
第二行 n 個正整數,每兩個整數之間用一個空格隔開,按標號順序分別表示這 n 個城市的商品價格。
接下來 m 行,每行有 3 個正整數,x,y,z,每兩個整數之間用一個空格隔開。
如果z=1,表示這條道路是城市 x 到城市 y 之間的單向道路;如果z=2,表示這條道路爲城市 x 和城市 y 之間的雙向道路。
輸出格式
一個整數,表示答案。
數據範圍
1≤n≤100000
1≤m≤500000
1≤各城市水晶球價格≤100

輸入樣例:
5 5
4 3 5 6 1
1 2 1
1 4 1
2 3 2
3 5 1
4 5 2
輸出樣例:
5

思路:

題意可以簡化爲,從1出發,到n結束,中間路徑任意,然後在每一個城市買入,再另一個城市賣出,求最大收益。
即求一條路徑,在a城市買入,在b城市賣出,使b-a最大且需先經過a再經過b。
跑一次最短路可以獲得到從城市1到X城市爲止最低或最高的價格,這樣兩次最短路就可以分別得到最低買入價和最高賣出價;又因爲需先經過a再經過b,所以第二次最短路的時候跑反圖(反圖即將原圖所有邊方向取反)可以得到從城市n到X城市爲止最低或最高的價格。
這樣得到的兩個數組dis[i]表示從城市1到X城市爲止最低價格,dis1[i]表示從城市n到X城市爲止最高價格,保證了dis1[i]表示的城市一定在dis[i]表示的城市後面

#include <bits/stdc++.h>
using namespace std;
struct stu
{
    int next;
};
vector<stu> tu[500010],fan[500010];
int pri[100010],dis[100010],dis1[100010],vis[100010];
void add(int s,int e){
    stu t;
    t.next=e;
    tu[s].push_back(t);   //原圖
    t.next=s;
    fan[e].push_back(t);  //反圖
}
void spfa(int s)  //跑最低價格
{
    queue<int> t;
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    t.push(s);
    dis[s]=pri[s];
    vis[s]=1;
    while(!t.empty()){
        int x=t.front();
        t.pop();
        vis[s]=0;
        for(int i=0;i<tu[x].size();i++){
            int v=tu[x][i].next;
            if(dis[v]>min(pri[v],dis[x])){
                dis[v]=min(pri[v],dis[x]);
                if(!vis[v]){
                    vis[v]=1;
                    t.push(v);
                }
            }
        }
    }
}
void fspfa(int s)   //跑最高價格
{
    queue<int> t;
    memset(dis1,0,sizeof(dis1));
    memset(vis,0,sizeof(vis));
    t.push(s);
    dis1[s]=pri[s];
    vis[s]=1;
    while(!t.empty()){
        int x=t.front();
        t.pop();
        vis[s]=0;
        for(int i=0;i<fan[x].size();i++){
            int v=fan[x][i].next;
            if(dis1[v]<max(pri[v],dis1[x])){
                dis1[v]=max(pri[v],dis1[x]);
                if(!vis[v]){
                    vis[v]=1;
                    t.push(v);
                }
            }
        }
    }
}
int main()
{
    int n,m,z,x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&pri[i]);
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y);
        if(z==2)
            add(y,x);
    }
    spfa(1);
    fspfa(n);
    int ans=0;
    for(int i=1;i<=n;i++){
        //printf("%d %d\n",dis1[i],dis[i]);
        ans=max(ans,dis1[i]-dis[i]);  //得到最高差價
    }
    printf("%d\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章