最優貿易(DP)

題目

題目描述

CC國有nn個大城市和mm 條道路,每條道路連接這 nn個城市中的某兩個城市。任意兩個城市之間最多隻有一條道路直接相連。這 mm 條道路中有一部分爲單向通行的道路,一部分爲雙向通行的道路,雙向通行的道路在統計條數時也計爲 11條。

CC國幅員遼闊,各地的資源分佈情況各不相同,這就導致了同一種商品在不同城市的價格不一定相同。但是,同一種商品在同一個城市的買入價和賣出價始終是相同的。

商人阿龍來到 CC 國旅遊。當他得知同一種商品在不同城市的價格可能會不同這一信息之後,便決定在旅遊的同時,利用商品在不同城市中的差價賺回一點旅費。設 CC 國 n 個城市的標號從 1~ n1 n,阿龍決定從 11號城市出發,並最終在 nn 號城市結束自己的旅行。在旅遊的過程中,任何城市可以重複經過多次,但不要求經過所有 nn 個城市。阿龍通過這樣的貿易方式賺取旅費:他會選擇一個經過的城市買入他最喜歡的商品――水晶球,並在之後經過的另一個城市賣出這個水晶球,用賺取的差價當做旅費。由於阿龍主要是來 CC 國旅遊,他決定這個貿易只進行最多一次,當然,在賺不到差價的情況下他就無需進行貿易。

假設 CC國有 55個大城市,城市的編號和道路連接情況如下圖,單向箭頭表示這條道路爲單向通行,雙向箭頭表示這條道路爲雙向通行。

假設 1~n1 n 號城市的水晶球價格分別爲 4,3,5,6,14,3,5,6,1。

阿龍可以選擇如下一條線路:11->22->33->55,並在 22號城市以33 的價格買入水晶球,在 33號城市以55的價格賣出水晶球,賺取的旅費數爲 2。

阿龍也可以選擇如下一條線路11->44->55->44->55,並在第11次到達55 號城市時以 11的價格買入水晶球,在第 22次到達44 號城市時以66 的價格賣出水晶球,賺取的旅費數爲55。

現在給出 nn個城市的水晶球價格,mm 條道路的信息(每條道路所連接的兩個城市的編號以及該條道路的通行情況)。請你告訴阿龍,他最多能賺取多少旅費。

輸入格式

第一行包含 22 個正整數nn和 mm,中間用一個空格隔開,分別表示城市的數目和道路的數目。

第二行 n 個正整數,每兩個整數之間用一個空格隔開,按標號順序分別表示這 n 個城市的商品價格。

接下來 mm 行,每行有33個正整數x,y,zx,y,z,每兩個整數之間用一個空格隔開。如果 z=1z=1,表示這條道路是城市xx到城市yy之間的單向道路;如果z=2z=2,表示這條道路爲城市 xx和城市yy之間的雙向道路。

輸出格式

一 個整數,表示最多能賺取的旅費。如果沒有進行貿易,則輸出 00。

輸入輸出樣例

輸入 #1複製

5 5 
4 3 5 6 1 
1 2 1 
1 4 1 
2 3 2 
3 5 1 
4 5 2 

輸出 #1複製

5

說明/提示

【數據範圍】

輸入數據保證 11 號城市可以到達nn號城市。

對於 10%的數據,1≤n≤61≤n≤6。

對於 30%的數據,1≤n≤1001≤n≤100。

對於 50%的數據,不存在一條旅遊路線,可以從一個城市出發,再回到這個城市。

對於 100%的數據,1≤n≤1000001≤n≤100000,1≤m≤5000001≤m≤500000,1≤x1≤x,y≤ny≤n,1≤z≤21≤z≤2,1≤1≤各城市

水晶球價格≤100≤100。

 

題解&&分析

最開始的思路是tarjan+搜索,但是很有可能超時,所以不可做,想用Dijksra的方式做這道題,結果好像也不能做

n較大,自己以爲dp不可做

其實是可做的,用搜索+dp

dp[i]表示從1到i可以得到的最大利潤

那麼dp[i] = max(dp[pre] , a[i] - minn )

pre是前驅節點,a[i]表示第i個點的價格,minn表示搜索到的這條路的最小值

理解一下方程,也就是判斷第i個點賣不賣出去

但是如果直接暴力,很容易TLE&MLE

在觀察這個dp式,如果是找一條道路來更新的話,那麼這條道路有意義必須能夠更新i及其後面的點。

所以,就有兩種情況:

如果它能夠更新dp[i],那麼就一定有可能更新i後面的節點

否則,它如果這條道路最小价格比之前到i的道路最小价格更小,那麼它也有可能更新i後面的值

而除了這兩種情況,其他的道路就可以忽略了

代碼

#include <iostream>
#include <algorithm>
#include <vector>

#include <cstdlib>
#include <stack>
#include <climits>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
const int MAXN = 100003;
int n , m;
vector<int>G[MAXN];
int f[MAXN] , minn[MAXN];
int a[MAXN];
void dfs( int x , int mi , int pre ){
    bool flag = 0;
    mi = min( mi , a[x] );
    if( minn[x] > mi ) minn[x] = mi , flag = 1;
    int maxx = max( f[pre] , a[x] - mi );
    if( maxx > f[x] )
        f[x] = maxx , flag = 1;
    if( !flag ) return;
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v = G[x][i];
        dfs( v , mi , x ) ;
    }

}
int main(){
    scanf( "%d%d" , &n , &m );
    for( int i = 1 ; i <= n ; i ++ )
        scanf( "%d" , &a[i] );
    memset( minn , 0x7f , sizeof( minn ) );
    for( int i = 1 ; i <= m ; i ++ ){
        int x,  y ,z;
        scanf( "%d%d%d" , &x , &y , &z );
        G[x].push_back( y );
        if( z == 2 ) G[y].push_back( x );
    }
    dfs( 1 , 0x7f , 0 );
    printf( "%lld\n" , f[n] );
    return 0;
}

 

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