題目描述
C國有 n個大城市和 m 條道路,每條道路連接這 n個城市中的某兩個城市。任意兩個城市之間最多隻有一條道路直接相連。這 m 條道路中有一部分爲單向通行的道路,一部分爲雙向通行的道路,雙向通行的道路在統計條數時也計爲1條。
C國幅員遼闊,各地的資源分佈情況各不相同,這就導致了同一種商品在不同城市的價格不一定相同。但是,同一種商品在同一個城市的買入價和賣出價始終是相同的。
商人阿龍來到 C國旅遊。當他得知同一種商品在不同城市的價格可能會不同這一信息之後,便決定在旅遊的同時,利用商品在不同城市中的差價賺回一點旅費。設 C國 n 個城市的標號從 1~ 1n,阿龍決定從1號城市出發,並最終在 n號城市結束自己的旅行。在旅遊的過程中,任何城市可以重複經過多次,但不要求經過所有 n個城市。阿龍通過這樣的貿易方式賺取旅費:他會選擇一個經過的城市買入他最喜歡的商品――水晶球,並在之後經過的另一個城市賣出這個水晶球,用賺取的差價當做旅費。由於阿龍主要是來 C國旅遊,他決定這個貿易只進行最多一次,當然,在賺不到差價的情況下他就無需進行貿易。
假設C國有 5個大城市,城市的編號和道路連接情況如下圖,單向箭頭表示這條道路爲單向通行,雙向箭頭表示這條道路爲雙向通行。
假設 1~1n 號城市的水晶球價格分別爲 4,3,5,6,1。
阿龍可以選擇如下一條線路:1->2->3->5,並在2號城市以3的價格買入水晶球,在3號城市以5的價格賣出水晶球,賺取的旅費數爲2。
阿龍也可以選擇如下一條線路 1->4->5->4->5,並在第1次到達5號城市時以1的價格買入水晶球,在第 2 次到達 4 號城市時以 6 的價格賣出水晶球,賺取的旅費數爲 5。
現在給出 n個城市的水晶球價格,m條道路的信息(每條道路所連接的兩個城市的編號以及該條道路的通行情況)。請你告訴阿龍,他最多能賺取多少旅費。
輸入格式
第一行包含 2 個正整數 n 和 m,中間用一個空格隔開,分別表示城市的數目和道路的數目。
第二行 n 個正整數,每兩個整數之間用一個空格隔開,按標號順序分別表示這 n 個城市的商品價格。
接下來 m 行,每行有 3個正整數x,y,z每兩個整數之間用一個空格隔開。如果 z=1,表示這條道路是城市 x到城市 y之間的單向道路;如果 z=2,表示這條道路爲城市 x和城市 y之間的雙向道路。
輸出格式
一 個整數,表示最多能賺取的旅費。如果沒有進行貿易,則輸出0。
輸入輸出樣例
輸入 #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
分析&說明:
這道題是要用SPFA做才合適,而且通過學校一位大佬的講解,
才知道:
這道題要用兩張圖:一張原圖,一張反圖。而且要跑兩遍SPFA,分別算出貿易的最小值與最大值,在最後求出max(最大值與最小值的差),就是最優貿易。
CODE:
這可能是我打過最長的代碼了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,a[100100],maxn[1000100]/*最大值數組*/,minn[1000100]/*最小值數組*/,v[1010001],f[1000100],ans;
struct node{
int x,y,next,w;
}c[1000010],b[1000010];
int tot,tot2,head1[1001000],head2[1001000];//這些變量都有兩個,兩張圖,兩遍spfa
void add(int x,int y,int w)
{
tot++;
b[tot].x=x;
b[tot].y=y;
b[tot].w=w;
b[tot].next=head1[x];
head1[x]=tot;
//第一張鄰接表
}
void add2(int x,int y,int w)
{
tot2++;
c[tot2].x=x;
c[tot2].y=y;
c[tot2].w=w;
c[tot2].next=head2[x];
head2[x]=tot2;
//第二張鄰接表
}
void spfa(int x)
{
//最小值spfa
memset(minn,0x7f,sizeof(minn)); //初值
minn[x]=a[x];
v[x]=1;
f[1]=x;
int head=0,tail=1;
while(head<tail) //類似廣搜實現
{
head=head%100010+1;
int x2=f[head];
for(int i=head1[x2];i;i=b[i].next) //鄰接表
{
if(minn[b[i].y]>min(a[b[i].y],minn[x2]))
{
minn[b[i].y]=min(a[b[i].y],minn[x2]); //求最小
if(!v[b[i].y])
{
tail++; //入隊
v[b[i].y]=1;
f[tail]=b[i].y;
}
}
}
v[x2]=0;
}
}
void spfa2(int x)
{
//最大值spfa
int head=0,tail=1;
memset(v,0,sizeof(v)); //初值
maxn[x]=a[x];
v[x]=1;
f[1]=x;
while(head<tail)
{
head=head%100010+1;
int x2=f[head];
for(int i=head2[x2];i;i=c[i].next)
{ //鄰接表
if(maxn[c[i].y]<max(a[c[i].y],maxn[x2]))
{
maxn[c[i].y]=max(a[c[i].y],maxn[x2]); //求最大
if(v[c[i].y]==0)
{
tail++; //繼續入隊
v[c[i].y]=1;
f[tail]=c[i].y;
}
}
}
v[x2]=0;
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
{
int x,y,k;
cin>>x>>y>>k;
if(k==1)
{
add(x,y,a[y]);
add2(y,x,a[x]);
}
else
{
add(x,y,a[y]);
add(y,x,a[x]); //原圖
add2(x,y,a[y]);
add2(y,x,a[x]); //反圖
}
}
spfa(1);spfa2(n);ans=0; //跑最大值與最小值spfa
for(int i=2;i<n;i++)
ans=max(ans,maxn[i]-minn[i]); //最大差
cout<<ans;
return 0;
}