1. 程式人生 > >【計算幾何】Car的旅行路線【NOIP2…

【計算幾何】Car的旅行路線【NOIP2…

Car的旅行路線【NOIP2001提高組】

Time Limit:10000MS  Memory Limit:65536K
Total Submit:18 Accepted:7

Description

  又到暑假了,住在城市A的Car想和朋友一起去城市B旅遊。她知道每個城市都有四個飛機場,分別位於一個矩形的四個頂點上,同一個城市中兩個機場之間有一條筆直的高速鐵路,第I個城市中高速鐵路了的單位里程價格為Ti,任意兩個不同城市的機場之間均有航線,所有航線單位里程的價格均為t。
圖例

【計算幾何】Car的旅行路線【NOIP2001提高組】 <wbr>pascal <wbr>解題報告


  那麼Car應如何安排到城市B的路線才能儘可能的節省花費呢?她發現這並不是一個簡單的問題,於是她來向你請教。
任務:
  找出一條從城市A到B的旅遊路線,出發和到達城市中的機場可以任意選取,要求總的花費最少。
  輸入:檔案輸入。
  輸出:輸出最小費用,小數點後保留1位。
輸入格式:
  第一行為一個正整數n(0 <= n <= 10),表示有n組測試資料。
  每組的第一行有四個正整數s,t,A,B。s(0 < s <= 100)表示城市的個數,t表示飛機單位里程的價格,A,B分別為城市A,B的序號,(1 <= A,B <= S)。
  接下來有S行,其中第I行均有7個正整數xi1,yi1,xi2,yi2,xi3,yi3,Ti,這當中的(xi1,yi1),(xi2,yi2),(xi3,yi3)分別是第I個城市中任意三個機場的座標,T I為第I個城市高速鐵路單位里程的價格。
輸出格式:
  共有n行,每行一個數據對應測試資料。

樣例:
輸入
1
1 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3

輸出:
47.55
 

Input

Output

Sample Input

Sample Output

Source

(1) 首先判斷直角的位置:【計算幾何】Car的旅行路線【NOIP2001提高組】 <wbr>pascal <wbr>解題報告
  因為從測試資料檔案中讀入的三個點的座標是無序的,因此需判斷直角的位置,然後在計算第四個點的座標。如圖,對於線段L1、L2,如果(x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)=0,那麼L1 ⊥ L2。
  (2) 計算(x4,y4):
  如圖:由x4-x3=x1-x2得x4=x1-x2+x3,同樣的y4=y1-y2+y3
  (3) 用鄰接表或鄰接矩陣把各個(機場)點之間的連線關係表示出來。
  (4) 計算各條高速鐵路的長度l,並求出每個城市中每條高速鐵路的總價:Ti * l
  (5) 計算各條飛機航線的長度l',並求出每條航線的總價:t * l'
  用Dijkstra計算各點間的最短路徑,求出費用最少的路線。

  DIJKSTRA演算法演算法思想:

  設定一個頂點集合S並不斷地作貪心選擇來擴大這個集合。一個頂點屬於集合S當且僅當從源到該頂點的最短路徑長度已知。初始時,S中僅含有源。設u是G的某一個頂點,把從源到u且中間只經過S中頂點的路稱為從源到u的特殊路徑,並用陣列dist記錄當前每個頂點所對應的最短特殊路徑長度。DIJKSTRA演算法每次從V-S中取出具有最短特殊路長度的頂點u,將u新增到S中,同時對陣列dist做必要的修改。一旦S包含了所有V中的頂點,dist就記錄了從源到所有其他頂點之間的最短路徑長度。

var

r:real;

n,s,t,a,b:longint;

f:array[1..100*4+1,1..100*4+1]of real;

c:array[1..100,1..4,1..2]of longint;

ti:array[1..100]of longint;

procedure make4(x1,y1,x2,y2,x3,y3,i:longint);

begin

if (x2-x1)*(x3-x1)+(y2-y1)*(y3-y1)=0 then

begin c[i,4,1]:=x3-x1+x2; c[i,4,2]:=y3-y1+y2; end;

if (x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)=0 then

begin c[i,4,1]:=x3+x1-x2; c[i,4,2]:=y3+y1-y2; end;

if (x2-x3)*(x1-x3)+(y2-y3)*(y1-y3)=0 then

begin c[i,4,1]:=-x3+x1+x2; c[i,4,2]:=-y3+y1+y2; end;

end;

procedure init;

var

i:longint;

begin

read(s,t,a,b);

for i:=1 to s do

begin

read(c[i,1,1],c[i,1,2],c[i,2,1],c[i,2,2],c[i,3,1],c[i,3,2],ti[i]);

make4(c[i,1,1],c[i,1,2],c[i,2,1],c[i,2,2],c[i,3,1],c[i,3,2],i);

end;

end;

procedure getf;

var

i,j,k,k1,k2:longint;

begin

for i:=1 to 400 do

for j:=1 to 400 do

if i<>j then f[i,j]:=maxlongint

else f[i,j]:=0;

for k:=1 to s do

for i:=1 to 4 do

for j:=1 to 4 do

if i<>j then

f[(k-1)*4+i,(k-1)*4+j]:=ti[k]*sqrt(sqr(c[k,i,1]-c[k,j,1])+sqr(c[k,i,2]-c[k,j,2]));

for k1:=1 to s do

for i:=1 to 4 do

for k2:=1 to s do

if k1<>k2 then

for j:=1 to 4 do

f[(k1-1)*4+i,(k2-1)*4+j]:=t*sqrt(sqr(c[k1,i,1]-c[k2,j,1])+sqr(c[k1,i,2]-c[k2,j,2]));

end;

procedure dij(x:longint);

var

temp,min:real;

j,mini:longint;

d:array[1..400]of real;

mark:array[1..400]of boolean;

begin

fillchar(mark,sizeof(mark),0);

for j:=1 to 400 do d[j]:=maxlongint;

d[x]:=0;

while true do

begin

min:=maxlongint;

for j:=1 to s*4 do

if (not mark[j])and(d[j]<min) then

begin

min:=d[j];

mini:=j;

end;

mark[mini]:=true;

if (mini-1) div 4=b-1 then

begin

if d[mini]<r then r:=d[mini];

exit;

end;

for j:=1 to s*4 do

if (not mark[j])and(f[mini,j]>0)then

begin

temp:=f[mini,j]+d[mini];

if temp<d[j] then d[j]:=temp;

end;

end;

end;

procedure main;

var

i:longint;

begin

r:=maxlongint;

getf;

for i:=1 to 4 do

dij((a-1)*4+i);

writeln(r:0:1);

end;

begin

read(n);

while n<>0 do

begin

dec(n);

init;

main;

end;

end.