【最短路+dijkstra+有難度】杭電 hdu 1245 Saving James Bond



/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
Copyright (c) 2011 panyanyany All rights reserved.

URL : http://acm.hdu.edu.cn/showproblem.php?pid=1245
Name : 1245 Saving James Bond

Date : Tuesday, January 17, 2012
Time Stage : 8 hours

Result:
52686632012-01-17 16:34:56Accepted1245
203MS320K4753 B
C++pyy


Test Data :

Review :
耗時8小時左右,十次提交,終於AC,也算是我做的少有的大題目了,唔,
以后要多做一些大題目啊。

據說此題卡精度……
//----------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std ;

#define MEM(a, v)memset (a, v, sizeof (a))
#define min(x, y)((x) < (y) ? (x) : (y))
#define max(x, y)((x) > (y) ? (x) : (y))
#define SQR(x)((x)*(x))

#define EPS1e-8
#define GT(x, y)(((x) - (y)) > EPS)// 大於
#define EQ(x, y)(fabs((x) - (y)) <= EPS)// 等於
#define LT(x, y)GT(y, x)// 小於
#define GET(x, y)(!LT(x, y))// >=
#define LET(x, y)(!GT(x, y))// <=

#define INF0x3f3f3f3f
#define MAXN103
#define DELTA50
#define RADIUS7.5

inline double getdist (int i, int j) ;

typedef struct tagPOINT {
int x, y ;
} POINT ;

struct EDGE {
int des ;
double dis ;
EDGE () {}
EDGE (int e, double ds) :
des(e), dis(ds) {}
};

boolused[MAXN] ;

intn, cnt ;
intstep[MAXN] ;

doubled ;
doubledist[MAXN] ;

vector<EDGE>graph[MAXN] ;// store edges

POINTmap[MAXN] ;

void init ()
{
int i ;
for (i = 0 ; i < MAXN ; ++i)
graph[i].clear () ;
memset (map, 0, sizeof (map)) ;
}

inline double getdist (double x1, double y1, double x2, double y2)
{
return sqrt (SQR(x1-x2) + SQR(y1-y2)) ;
}

inline double getdist (int i, int j)
{
return getdist (map[i].x, map[i].y, map[j].x, map[j].y) ;
}

inline double tostart (int i)
{
// RADIUS : 別忘了小島是有半徑的,一開始把 diameter 看成是半徑了,暈死啊
return getdist (map[i].x, map[i].y, DELTA, DELTA) - RADIUS;
}

inline double toend (int i)
{
return min (
min (map[i].x, map[i].y),
min (abs (100-map[i].x), abs(100-map[i].y))) ;
}

void makegraph ()
{
int i, j ;
double s, e ;
for (i = 1 ; i <= n ; ++i)
{
// 到小島的距離
s = tostart (i) ;
// 到岸邊的距離
e = toend (i) ;
// 從小島可以直接跳上的點
if (GT(s, 0) && GET(d, s))
graph[0].push_back(EDGE(i, s)) ;
// 可以直接跳到岸上的點
if (GT(e, 0) && GET(d, e))
graph[i].push_back(EDGE(n+1, e)) ;
}

// 各點到各點的可行的邊
for (i = 1 ; i <= n ; ++i)
for (j = 1 ; j <= n ; ++j)
{
if (i == j)
continue ;
s = getdist (i, j) ;
if (GET(d, s))
{
graph[i].push_back(EDGE(j, s)) ;
}
}
}

// dijkstra 中處理的各點都應具有平等的身份,這樣才能方便處理,
// 像 “小島” 和 “岸邊”這種特殊情況要想辦法預先轉化為與“點”
// 一樣的角色
void dijkstra (const int start, const int end)
{
int i, j, id ;
int iMinPath ;
double MinPath, s ;

MEM (step, 0) ;
MEM (used, 0) ;

for (i = start ; i <= end ; ++i)
dist[i] = INF * 1.0 ;

// 從小島可以直接跳上的點
for (i = 0 ; i < graph[start].size() ; ++i)
{
id = (graph[start][i]).des ;
dist[id] = graph[start][i].dis ;
step[id] = 1 ;
}

for (j = start ; j <= end ; ++j)
{
iMinPath = 0 ;
MinPath = INF * 1.0 ;

for (i = start ; i <= end ; ++i)
if (!used[i] && dist[i] < MinPath)
{
iMinPath = i ;
MinPath = dist[i] ;
}

used[iMinPath] = 1 ;

for (i = 0 ; i < graph[iMinPath].size() ; ++i)
{
// 能從 iMinPath 到達的點 id
id = graph[iMinPath][i].des ;
// 原路徑加上 邊(iMinPath, id) 的距離
s = dist[iMinPath] + graph[iMinPath][i].dis ;

if (!used[id] && LT(s, dist[id]))
{
dist[id] = s ;
step[id] = step[iMinPath] + 1 ;
}
}
}
}

int main ()
{
int i ;
int x, y ;
while (~scanf ("%d%lf", &n, &d))
{
init () ;
for (i = 1 ; i <= n ; ++i)
{
scanf ("%d%d", &x, &y) ;
// DELTA 的意思,是把整幅圖向右向上各平移了 DELTA 個單位
map[i].x = x + DELTA ;
map[i].y = y + DELTA ;
}

// 可以一步直接跳出來的,直接輸出
// 本來是想直接輸出 d 而不是 50-RADIUS 的,
// 但考慮到 James Bond 應該不至於每一步都固定吧
if (GET(d, 50-RADIUS))
printf ("%.2lf %d\n", 50-RADIUS, 1) ;
else
{
// 建圖,處理小島和岸邊這兩大麻煩。
// 參考大牛的做法,把這兩處處理成兩點:0 和 n+1
// 其實我感覺本題的難處可能就是處理這兩點的問題上
// 因為一開始想不到什么好辦法,於是在 dijkstra 中處理
// 結果弄得很麻煩,因為問題分散了,一開始沒有建好圖,
// 后面就要步步驚心地小心注意區分好 "小島、岸邊與各點"
// 總之一句話:把問題在源頭處理好,就不會污染整個流程了!
makegraph () ;
dijkstra(0, n+1) ;
if (LT(dist[n+1], INF * 1.0))
printf ("%.2lf %d\n", dist[n+1], step[n+1]) ;
else
puts ("can't be saved") ;
}
}
return 0 ;
}



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com