題目
題目描述
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可以得到的最大利潤
那麼
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;
}