### 【最短路+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=1245Name  : 1245 Saving James BondDate  : Tuesday, January 17, 2012Time Stage : 8 hoursResult: 52686632012-01-17 16:34:56Accepted1245203MS320K4753 BC++pyyTest 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.5inline 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 edgesPOINTmap[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 到達的點 idid = 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]) ;elseputs ("can't be saved") ;}}return 0 ;}`