From Admin
背景 Background
NOIP2009第三題
描述 Description
C 國有n 個大城市和m 條道路,每條道路連接這n 個城市中的某兩個城市。任意兩個
城市之間最多隻有一條道路直接相連。這m 條道路中有一部分爲單向通行的道路,一部分
爲雙向通行的道路,雙向通行的道路在統計條數時也計爲1 條。
C 國幅員遼闊,各地的資源分佈情況各不相同,這就導致了同一種商品在不同城市的價
格不一定相同。但是,同一種商品在同一個城市的買入價和賣出價始終是相同的。
商人阿龍來到 C 國旅遊。當他得知同一種商品在不同城市的價格可能會不同這一信息
之後,便決定在旅遊的同時,利用商品在不同城市中的差價賺回一點旅費。設C 國n 個城
市的標號從1~ n,阿龍決定從1 號城市出發,並最終在n 號城市結束自己的旅行。在旅遊的過程中,任何城市可以重複經過多次,但不要求經過所有n 個城市。阿龍通過這樣的貿易方式賺取旅費:他會選擇一個經過的城市買入他最喜歡的商品——水晶球,並在之後經過的另一個城市賣出這個水晶球,用賺取的差價當做旅費。由於阿龍主要是來C 國旅遊,他決定這個貿易只進行最多一次,當然,在賺不到差價的情況下他就無需進行貿易。
假設 C 國有5 個大城市,城市的編號和道路連接情況如下圖,單向箭頭表示這條道路
爲單向通行,雙向箭頭表示這條道路爲雙向通行。
假設 1~n 號城市的水晶球價格分別爲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 條道路的信息(每條道路所連接的兩個城市的編號以及該條道路的通行情況)。請你告訴阿龍,他最多能賺取多少旅費。
輸入格式 Input Format
第一行包含 2 個正整數n 和m,中間用一個空格隔開,分別表示城市的數目和道路的
數目。
第二行 n 個正整數,每兩個整數之間用一個空格隔開,按標號順序分別表示這n 個城
市的商品價格。
接下來 m 行,每行有3 個正整數,x,y,z,每兩個整數之間用一個空格隔開。如果z=1,表示這條道路是城市x 到城市y 之間的單向道路;如果z=2,表示這條道路爲城市x 和城市y 之間的雙向道路。
輸出格式 Output Format
第一行包含 2 個正整數n 和m,中間用一個空格隔開,分別表示城市的數目和道路的
數目。
第二行 n 個正整數,每兩個整數之間用一個空格隔開,按標號順序分別表示這n 個城
市的商品價格。
接下來 m 行,每行有3 個正整數,x,y,z,每兩個整數之間用一個空格隔開。如果z=1,表示這條道路是城市x 到城市y 之間的單向道路;如果z=2,表示這條道路爲城市x 和城市y 之間的雙向道路。
樣例輸入 Sample Input [複製數據]
樣例輸出 Sample Output [複製數據]
時間限制 Time Limitation
1s
註釋 Hint
【數據範圍】
輸入數據保證 1 號城市可以到達n 號城市。
對於 10%的數據,1≤n≤6。
對於 30%的數據,1≤n≤100。
對於 50%的數據,不存在一條旅遊路線,可以從一個城市出發,再回到這個城市。
對於 100%的數據,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市
水晶球價格≤100。
首先,認真的閱讀此題。有多少人以爲隨便哪個點都能出發。然後就掛了。讀題,理解題目,永遠比寫程序更重要。
標準解法是 求強連通分量+topsort+縮點dp
我topsort+dp莫名其妙的過了= =
f[i]表示1..i中最小的買進價格
ans=max(p[i]-f[i]) i爲1..n之間的拓撲序列
dfs求拓撲序列
dfs1通過反向邊,標記能達到n的結點。
鏈式前向星構圖
var i,n,m,a1,b1,c1,kk,len,ans,tot:longint;
p,tt,t,f,ff:array[1..100000]of longint;
v,v1,hash:array[1..100000]of boolean;
next,e,head,next1,e1,head1:array[1..1000000]of longint;
procedure insert(a,b,i:longint);
begin
next[i]:=head[a];
e[i]:=b;
head[a]:=i;
end;
procedure insert1(a,b,i:longint);
begin
next1[i]:=head1[a];
e1[i]:=b;
head1[a]:=i;
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
procedure dfs(k:longint);
var i:longint;
begin
v[k]:=true;
i:=head[k];
while i<>0 do
begin
if not(v[e[i]]) then dfs(e[i]);
i:=next[i];
end;
tt[kk]:=k;
dec(kk);
end;
procedure dfs1(k:longint);
var i:longint;
begin
v[k]:=true;v1[k]:=true;
i:=head1[k];
while i<>0 do
begin
if not(v[e1[i]]) then dfs1(e1[i]);
i:=next1[i];
end;
end;
procedure dp(k:longint);
var i:longint;
begin
i:=head1[k];
while i<>0 do
begin
if (v1[e1[i]])and(hash[e1[i]]) then f[k]:=min(f[k],f[e1[i]]);
i:=next1[i];
end;
end;
procedure work;
var i:longint;
begin
fillchar(v,sizeof(v),false);
dfs1(n);
end;
procedure topsort;
var i,l1,r1:longint;
begin
for i:=1 to n do if not(v[i]) then dfs(i);
for i:=1 to n do
begin
if tt[i]=1 then l1:=i;
if tt[i]=n then r1:=i;
end;
len:=0;ans:=0;
for i:=l1 to r1 do
begin
inc(len);
t[len]:=tt[i];
end;
work;
for i:=1 to len do hash[t[i]]:=true;
for i:=1 to n do f[i]:=p[i];
for i:=1 to len do if v1[t[i]]=true then dp(t[i]);
for i:=1 to len do
if ans<p[t[i]]-f[t[i]] then ans:=p[t[i]]-f[t[i]];
writeln(ans);
end;
begin
fillchar(f,sizeof(f),0);fillchar(v1,sizeof(v1),false);
fillchar(v,sizeof(v),false);fillchar(hash,sizeof(hash),false);
readln(n,m);kk:=n;
for i:=1 to n do read(p[i]);
for i:=1 to m do
begin
readln(a1,b1,c1);
if c1=1 then
begin
insert(a1,b1,i);
insert1(b1,a1,i);
end;
if c1=2 then
begin
insert(a1,b1,i*2);insert(b1,a1,i*2+1);
insert1(a1,b1,i*2);insert1(b1,a1,i*2+1);
end;
end;
topsort;
readln;readln;
end.