/* 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:
5268663 2012-01-17 16:34:56 Accepted 1245
203MS 320K 4753 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 EPS 1e-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 INF 0x3f3f3f3f
#define MAXN 103
#define DELTA 50
#define RADIUS 7.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) {}
};
bool used[MAXN] ;
int n, cnt ;
int step[MAXN] ;
double d ;
double dist[MAXN] ;
vector<EDGE> graph[MAXN] ; // store edges
POINT map[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 ;
}