Saving James Bond - Hard Version

题目翻译:

这一次让我们想想电影《生死存亡》中的场景,世界上最著名的间谍詹姆斯·邦德被一群毒贩抓获。他被派到一个满是鳄鱼的湖中心的一小块土地上。在那里,他采取了最大胆的逃跑行动——他跳到最近的鳄鱼的头上!在那只动物意识到发生了什么之前,詹姆斯又跳到了另一个大脑袋上……最后,在最后一条鳄鱼咬他之前,他终于到达了岸边(实际上,这位特技演员被鳄鱼的大嘴抓住了,并用他那特别厚的靴子勉强逃脱)。
假设这个湖是一个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;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值