# bzoj 1665: The Climbing Wall 攀岩 最短路

## Description

One of the most popular attractions at the county fair is the climbing wall. Bessie wants to plan her trip up the wall in advance and needs your help. The wall is 30,000 millimeters wide and H (1001 <= H <= 30,000) millimeters high and has F (1 <= F <= 10,000) hoof-holds at unique X,Y coordinates expressed in millimeters. 0,0 is at the ground level on the left side of the wall. Hoof-holds are separated by at least 300 millimeters since no cow can maneuver them if they are spaced too close! Bessie knows there is at least one way up. Bessie, through techniques only she knows, uses successive single hoof-holds to climb the wall. She can only move from one hoof-hold to another if they are no more than one meter apart. She can, of course, move up, down, right, left or some combination of these in each move. Similarly, once she gets to a hoof-hold that is at least H-1000 millimeters above the ground, she can nimbly climb from there onto the platform atop the wall. Bessie can start at any X location that has a Y location <= 1000 millimeters. Given the height of the wall and the locations of the hoof-holds, determine the smallest number of hoof-holds Bessie should use to reach the top.

Bessie参加了爬墙比赛，比赛用的墙宽30000,高H(1001 <= H <= 30,000)。墙上有F(1 <= F <= 10,000)个不同的落脚点（X，Y）。 （0，0）在左下角的地面。所有的落脚点至少相距300。Bessie知道至少有一条路可以上去。 Bessie只能从一个落脚点爬到另一个距离不超过1000的落脚点，她可以向上下左右四个方向爬行。同样地，一旦她到达了一个高度 至少有H-1000的落脚点，她可以敏捷地爬到墙顶上。Bessie一开始可以在任意一个高度不超过1000的落脚点上。问Bessie至少攀爬多少次.这里两个点的距离都是欧几里得距离

## Input

* Line 1: Two space-separated integers, H and F.

* Lines 2..F+1: Each line contains two space-separated integers (respectively X and Y) that describe a hoof-hold. X is the distance from the left edge of the climbing wall; Y is the distance from the ground.

## Output

* Line 1: A single integer that is the smallest number of hoof-holds Bessie must use to reach the top of the climbing wall.

感觉这道题可以作为建边的超级源超级汇的第一题来做。

这道题题目上建边的方式已经告诉你了，起点可以在任意一个高度<=1000的点，在高度与墙高差在1000以内的距离走一步即为终点。那么第一想法肯定是在每一个能做起点的点开始跑最短路，然后暴力判断每一个能做终点的点。不过这么频繁的跑最短路肯定超时，所以我们可以自己创造一个超级源点，将能作为起点的点与这个超级原点连一条距离为0的边，再创造一个超级汇点，给能上墙的点与它连一条长度为1的边。这样从这个超级源点开始跑最短路，最终答案就是这个超级汇点的距离啦。

下附AC代码。

#include<iostream>
#include<vector>
#include<queue>
#include<stdio.h>
#include<string.h>
#define maxn 10005
using namespace std;
struct nod
{
int nex,dis;
nod(int a,int b)
{
nex=a;
dis=b;
}
nod(){}
};
vector<nod>edge[maxn];
int h,n,w;
int vis[maxn];
int dis[maxn];
int pre[maxn];
queue<int> q;
int getfront()
{
int ans=q.front();
q.pop();
vis[ans]=0;
return ans;
}
void insert(int now)
{
if(vis[now]==1) 	return;
q.push(now);
vis[now]=1;
return;
}
void spfa(int start)
{
memset(dis,-1,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[start]=0;
insert(start);
while(!q.empty())
{
int now=getfront();
int len=edge[now].size();
for(int j=0;j<len;j++)
{
nod temp=edge[now][j];
if(dis[temp.nex]==-1 || dis[temp.nex]>dis[now]+temp.dis)
{
dis[temp.nex]=dis[now]+temp.dis;
pre[temp.nex]=now;
insert(temp.nex);
}
}
}
}
int x[maxn],y[maxn];
int diss(int i,int j)
{
return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
int main()
{
scanf("%d%d",&h,&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}

for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(diss(i,j)<=1000*1000)
{
edge[i].push_back(nod(j,1));
edge[j].push_back(nod(i,1));
}
if(y[i]<=1000)
{
edge[0].push_back(nod(i,0));
}
if(h-y[i]<=1000)
{
edge[i].push_back(nod(n+1,1));
}
}
spfa(0);
printf("%d\n",dis[n+1]);
}