题目翻译:
这一次让我们想想电影《生死存亡》中的场景,世界上最著名的间谍詹姆斯·邦德被一群毒贩抓获。他被派到一个满是鳄鱼的湖中心的一小块土地上。在那里,他采取了最大胆的逃跑行动——他跳到最近的鳄鱼的头上!在那只动物意识到发生了什么之前,詹姆斯又跳到了另一个大脑袋上……最后,在最后一条鳄鱼咬他之前,他终于到达了岸边(实际上,这位特技演员被鳄鱼的大嘴抓住了,并用他那特别厚的靴子勉强逃脱)。
假设这个湖是一个100乘100的正方形。假设湖中心在(0,0)处,东北角在(50,50)处。中心岛是一个圆心在(0,0)直径为15的圆盘。许多鳄鱼在湖中处于不同的位置。给定每条鳄鱼的坐标和詹姆斯能跳的距离,你必须告诉他到达某一河岸的最短路径。路径的长度就是James要跳的次数。
输入规格:
每个输入文件包含一个测试用例。每一种情况都以一行开始,其中包含两个正整数N(≤100),即鳄鱼的数量,和D,即詹姆斯能跳的最大距离。然后是N行,每一行包含鳄鱼的(x,y)位置。注意,没有两只鳄鱼保持同一位置。
输出规范:
对于每个测试用例,如果James可以逃跑,则在一行中输出他必须进行的最小跳跃次数。然后从下一行开始,输出路径上每个鳄鱼的位置(x,y),每对在一行中,从岛屿到河岸。如果詹姆斯不可能通过这种方式逃跑,那就把他的跳跃次数设为0。如果有多个最短路径,只输出第一次跳数最小的那条,它保证是唯一的。
Sample Input 1:
17 15
10 -21
10 21
-40 10
30 -50
20 40
35 10
0 -10
-25 22
40 -40
-30 30
-10 22
0 11
25 21
25 10
10 10
10 35
-30 10
Sample Output 1:
4
0 11
10 21
10 35
Sample Input 2:
4 13
-12 12
12 12
-12 -12
12 -12
Sample Output 2:
0
1.岛半径7.5,而不是15;15是直径;
2.如果D足够一次跳出去的话,就不必通过跳鳄鱼逃生了;
3.可能有鳄鱼在岸上,或在岛上,这是不能跳的,应该先舍弃;在保存在鳄鱼池的鳄鱼坐标;
4.首先要求能安全上岸,在其中比较那个路径最短,若有相同的最短路径,则取第一次跳 距离最小的那个;
5.这是一道无权单源最短路径问题
(1).题目的本意是 广度优先搜索而非用Dijkstra算法,因为是无权图。
(2).首先收集可以跳第一步的点(第一跳不一样,我没有用将第一个点设为(0,0))
P 1,P 2…P x; 对这些点求出 判断能否安全逃脱,并记录路径(判断和记录同时进行)
函数为 Unweighted()(核心算法);
既然要记录每个可以安全逃逸的首个点,那么我用二维数组保存;dist[S][?],为首点,“?”为路过点,dist为记录路径长度,path为记录路径数组。
void Unweighted(int S,MGraph G){
dist[S][S]=0;
Queue Q=CreateQueue();
AddQ(Q,S);
int V;
while(!IsEmpty(Q)){
V=DeleteQ(Q);
if(IsSafe(G,V)){
answer=1;//全局变量,若是有一个首点可以逃脱就answer=1了
TrueFirstV[S]=1;
FinalV[S]=V;
break; //S为可以跳的首点,S对应的V是最后一条(可上岸的点)
} //寻找最后一点(可以跳上岸的那一点)
for(int W=0;W<G->Nv;W++){
if(dist[S][W]==-1 && Jump(G,W,V)){
dist[S][W]=dist[S][V]+1;
path[S][W]=V;
AddQ(Q,W);
}
}
}
}
(3)分析出各个能安全逃逸的首点后,进行比较,得出最佳的首点 “Best—S”即可 。
具体代码:
#include <stdio.h>
#include <stdlib.h>
struct VNode{
int x,y;
};
typedef struct VNode* Coord;
struct GNode{
int Nv;
int D;//最大跳跃距离
Coord Data;
};
typedef struct GNode* MGraph;
int dist[100][100];
int path[100][100];
int Jump(MGraph G,int W,int V){
int xx=G->Data[V].x-G->Data[W].x;
int yy=G->Data[V].y-G->Data[W].y;
if(xx*xx+yy*yy<=G->D*G->D)
return 1;
else
return 0;
}
int FirstJump(MGraph G,int V){
int xx=G->Data[V].x*G->Data[V].x;
int yy=G->Data[V].y*G->Data[V].y;
float Dis=(float)(G->D+7.5);
if(xx+yy<=Dis*Dis)
return 1;
else
return 0;
}
int IsSafe(MGraph G,int V){
if((50-abs(G->Data[V].x))<=G->D
||(50-abs(G->Data[V].y))<=G->D
)
return 1;
else return 0;
}
struct QNode{
int* Q;
int front,rear;
};
typedef struct QNode* Queue;
Queue CreateQueue(){
Queue Que=(Queue)malloc(sizeof(struct QNode));
Que->Q=(int*)malloc(sizeof(int)*100);
Que->front=Que->rear=0;
return Que;
}
int IsEmpty(Queue Que){
return (Que->front==Que->rear);
}
int IsFull(Queue Que){
return ((Que->rear+1)%100==Que->front);
}
void AddQ(Queue Que,int V){
if(IsFull(Que))
printf("the Queue is full.");
else{
Que->rear=(Que->rear+1)%100;
Que->Q[Que->rear]=V;
}
}
int DeleteQ(Queue Que){
if(IsEmpty(Que))
printf("the Queue is empty.");
else{
Que->front=(Que->front+1)%100;
return Que->Q[Que->front];
}
}
typedef struct SNode* Stack;
struct SNode{
int* Data;
int Top;
int MaxSize;
};
Stack CreateStack(int MaxSize){
Stack S=(Stack)malloc(sizeof(struct SNode));
S->Data=(int*)malloc(sizeof(int)*MaxSize);
S->Top=-1;
S->MaxSize=MaxSize;
return S;
}
int IsEmptyS(Stack S){
return (S->Top==-1);
}
int IsFullS(Stack S){
return (S->Top==S->MaxSize-1);
}
int Push(Stack S,int X){
if(IsFullS(S)){
printf("Stack is full");
return 0 ;
}
else{
S->Data[++S->Top] = X;
return 1;
}
}
int Pop(Stack S){
if(IsEmptyS(S)){
printf("Stack is empty!");
return 1;
}
else{
return S->Data[S->Top--];
}
}
int compare(MGraph G,int S,int BestS){
int disS=G->Data[S].x*G->Data[S].x
+G->Data[S].y*G->Data[S].y;
int disB=G->Data[BestS].x*G->Data[BestS].x
+G->Data[BestS].y*G->Data[BestS].y;
if(disS<disB)
return 1;
else
return 0;
}
int FindMin(int FirstV[],MGraph G){
int min=0;
for(int i=0;FirstV[i]!=-1;i++)
if(compare(G,min,i))
min=i;
return min;
}
int answer=0;
int First[100],TrueFirstV[100],FinalV[100];
void Unweighted(int S,MGraph G){
dist[S][S]=0;
Queue Q=CreateQueue();
AddQ(Q,S);
int V;
while(!IsEmpty(Q)){
V=DeleteQ(Q);
if(IsSafe(G,V)){
answer=1;
TrueFirstV[S]=1;
FinalV[S]=V;
break; //S为可以跳的首点,S对应的V是最后一条(可上岸的点)
} //寻找最后一点(可以跳上岸的那一点)
for(int W=0;W<G->Nv;W++){
if(dist[S][W]==-1 && Jump(G,W,V)){
dist[S][W]=dist[S][V]+1;
path[S][W]=V;
AddQ(Q,W);
}
}
}
}
void Save007(MGraph G){
for(int i=0;i<100;i++)
for(int j=0;j<100;j++){
dist[i][j]=-1;
path[i][j]=-1;
}
for(int i=0;i<100;i++){
First[i]=-1; //可跳的首点
TrueFirstV[i]=0;//可安全到达的 首点
FinalV[i]=-1; //索引为安全首点,对应值为最后一点
}
for(int i=0;i<G->Nv;i++)
if(FirstJump(G,i))
First[i]=i; //首点个数
for(int i=0;i<G->Nv;i++)
if(First[i]!=-1)
Unweighted(First[i],G);
// 对每一个首点进行最短路径算法;最后比较
if(!answer)
printf("0");
else{
int BestS,BestV;
int MinDis=10000;
for(int S=0;S<G->Nv;S++){ //要最短的路,再
if(TrueFirstV[S]){
if(dist[S][FinalV[S]]!=-1&&dist[S][FinalV[S]]<MinDis){
MinDis=dist[S][FinalV[S]];
BestS=S;
BestV=FinalV[S];
}
}
}
for(int S=0;S<G->Nv;S++){ //要最短的路,再
if(TrueFirstV[S]){
if(dist[S][FinalV[S]]==MinDis){
if(compare(G,S,BestS)){
BestS=S;
BestV=FinalV[S];
}
}
}
}
printf("%d\n",dist[BestS][BestV]+2);
//从(0,0)到第一点没算 ,最后一点到岸上没算 ;故最后加上
Stack s=CreateStack(100);
for(int X=BestV;path[BestS][X]!=-1;X=path[BestS][X]){
Push(s,X);
}
printf("%d %d\n",G->Data[BestS].x,G->Data[BestS].y);
while(!IsEmptyS(s)){
int v=Pop(s);
printf("%d %d\n",G->Data[v].x,G->Data[v].y);
}
}
}
int main(){
int N,D;
scanf("%d %d",&N,&D);
int x[N],y[N],cnt=0;
for(int i=0;i<N;i++){
scanf("%d %d",&x[i],&y[i]);
if(((x[i]*x[i]+y[i]*y[i])>=7.5*7.5) && abs(x[i])<=50 && abs(y[i])<=50){
cnt++;
}
}
MGraph Graph=(MGraph)malloc(sizeof(struct GNode));
Graph->Data=(Coord)malloc(sizeof(struct VNode)*cnt);
Graph->Nv=cnt;
Graph->D=D;
for(int i=0;i<cnt;i++){
Graph->Data[i].x=x[i];Graph->Data[i].y=y[i];
}
if(D+7.5>=50)
printf("1");
else Save007(Graph);
return 0;
}