[noip2009 T3][topsort+dp]最優貿易

最優貿易
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.


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