【計算幾何】Car的旅行路線【NOIP2…
Car的旅行路線【NOIP2001提高組】
Time Limit:10000MS Memory
Limit:65536K
Total Submit:18 Accepted:7
Description
又到暑假了,住在城市A的Car想和朋友一起去城市B旅遊。她知道每個城市都有四個飛機場,分別位於一個矩形的四個頂點上,同一個城市中兩個機場之間有一條筆直的高速鐵路,第I個城市中高速鐵路了的單位里程價格為Ti,任意兩個不同城市的機場之間均有航線,所有航線單位里程的價格均為t。
圖例
那麼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) 首先判斷直角的位置:因為從測試資料檔案中讀入的三個點的座標是無序的,因此需判斷直角的位置,然後在計算第四個點的座標。如圖,對於線段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.