聯合權值(codevs 3728)題解

【問題描述】

無向連通圖 G 有 n 個點,n-1 條邊。點從 1 到 n 依次編號,編號爲 i 的點的權值爲 Wi, 每條邊的長度均爲 1。圖上兩點(u, v)的距離定義爲 u 點到 v 點的最短距離。對於圖 G 上的點對(u, v),若它們的距離爲 2,則它們之間會產生Wu×Wv的聯合權值。請問圖 G 上所有可產生聯合權值的有序點對中,聯合權值最大的是多少?所有聯合權值之和是多少?

【樣例輸入】

    5

    1 2

    2 3

    3 4

    4 5

    1 5 2 3 10

【樣例輸出】

    20 74

【解題思路】

    第一次去提高組碰到的題目……沒錯NOIP2014……當時我那叫一個聰明啊,直接開了個鄰接矩陣。數據範圍那叫一個小啊,n<=200000啊,然後華麗麗地全部MLE……好吧,其實當時是因爲不會鄰接表,而且當時我的思路有點問題……數組範圍改小後也只過了3個點。

    下面來說正解。

    首先這道題必須要用鄰接表來存儲!(不會鄰接表的自行百度,把程序抄上去自己debug,自學是絲毫沒有問題的)然後,由於鄰接表的特性,我們可以直接求出所有兩點直接距離爲2的點對,即一個點直接連接的所有點的距離均爲2,對於每一個點所直接連接的點,我們可以存儲第一大和第二大的點,這兩個點的乘積最大的便是第一個問題的解。

    然後對於每一個點,如果我們一個個點對去找,是會TLE3個點的,那麼最好的方法是這樣的:我們知道一個點所直接連接的點兩兩之間都是有序點對,那麼,當我們搜到第n個點時,它所組成的所有點對的聯合權值爲前面所有點的權值加起來與它相乘(這是關鍵部分!!!不懂的自己算一算,想一想),由於題目中(1,3)和(3,1)算兩個不同的有序點對,因此我們需要把答案乘2。注意:在算答案的時候要邊算邊取模。下面貼代碼。

【代碼實現】

 1 type rec=record
 2      c,next:longint;
 3 end;
 4 var g:array[0..200010] of rec;
 5     e:array[0..400010] of rec;
 6     efree,n,u,v,i,j,k,max,ans,max1,max2,sum:longint;
 7     w:array[0..200010] of longint;
 8 procedure add(x:longint;var p:rec);
 9 begin
10  e[efree].c:=x;
11  e[efree].next:=p.next;
12  p.next:=efree;
13  inc(efree);
14 end;
15 begin
16  readln(n);
17  for i:=1 to n do
18   g[i].next:=-1;
19  efree:=1;
20  for i:=1 to n-1 do
21   begin
22    readln(u,v);
23    add(u,g[v]);
24    add(v,g[u]);
25   end;
26  for i:=1 to n do
27   read(w[i]);
28  for i:=1 to n do
29   begin
30    j:=g[i].next;
31    sum:=0;
32    max1:=0;
33    max2:=0;
34    while j<>-1 do
35     begin
36      k:=w[e[j].c];
37      if k>max1 then
38       max1:=k
39      else
40       if k>max2 then
41        max2:=k;
42      ans:=ans+(sum mod 10007)*k*2 mod 10007;
43      ans:=ans mod 10007;
44      inc(sum,k);
45      j:=e[j].next;
46     end;
47    if max1*max2>max then
48     max:=max1*max2;
49   end;
50  writeln(max,' ',ans);
51 end.

 

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