题目链接
前言:
这题细节真的有很多,真的很讨厌。
关键点:
1、本题与上题(easy)的不同点,该题要求的是007逃出岛的路径,因此要用到无权图单源最短路算法:
/* 邻接表存储 - 无权图的单源最短路算法 */
/* dist[]和path[]全部初始化为-1 */
void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S )
{
Queue Q;
Vertex V;
PtrToAdjVNode W;
Q = CreateQueue( Graph->Nv ); /* 创建空队列, MaxSize为外部定义的常数 */
dist[S] = 0; /* 初始化源点 */
AddQ (Q, S);
while( !IsEmpty(Q) ){
V = DeleteQ(Q);
for ( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */
if ( dist[W->AdjV]==-1 ) { /* 若W->AdjV未被访问过 */
dist[W->AdjV] = dist[V]+1; /* W->AdjV到S的距离更新 */
path[W->AdjV] = V; /* 将V记录在S到W->AdjV的路径上 */
AddQ(Q, W->AdjV);
}
} /* while结束*/
}
2、细节一:题目说的:
If there are many shortest paths, just output the one with the minimum first jump, which is guaranteed to be unique.
说明有可能有多条路径均为最短,那么就输出第一次从岛上跳到鳄鱼上最短的一条。
看到这里,我第一个想法是将所以最短的都存起来,后面判断,但是很快这种方法非常不好,最好在一开始就从最短的可以跳到鳄鱼上的路径开始选择,因此我修改了firstjump这个函数,让其既可以判断是否可以跳上鳄鱼,也可以返回长度,方便后序进行排序
int firstjump(int x)
{
double ju = sqrt(g[x][1]*g[x][1]+g[x][2]*g[x][2]);
if (ju<=7.5+d)
return ju;
else
return 0;
}
3、细节二:如何输出path:
很明显,递归是好想好写的
void findpath(int x, int start)
{
if (x==start)
{
printf("%d %d\n", g[start][1], g[start][2]);
return ;
}
findpath(path[x], start);
printf("%d %d\n", g[x][1], g[x][2]);
}
一直遍历start存的是第一次跳到鳄鱼的编号,因为输出样例是从第一只鳄鱼开始输出的,因此一直不断递归,指导递归到start,再分别输出。
4、细节三:
在写完整体代码提交后,很讨厌的是竟然还要排除鳄鱼在岛上,或在岸上的情况。
再写一个函数来判断:
int pan(int x, int y)
{
double ju = sqrt(x*x+y*y);
// printf("%f\n", ju);
if (ju<=7.5)
return 0;
if (x<=-50||x>=50||y<=-50||y>=50)
return 0;
return 1;
}
先根据距离来判断是否在岛上,再根据坐标判断是否在岸上。
5、细节五:考虑007腿超长,可以一脚就上岸边,
直接在开头判断
scanf("%d%d", &n, &d);
if (d>=50)
{
printf("1\n");
return 0;
}
真的是有很多细节啊,改的我,哎。
完整代码
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <algorithm>
using namespace std;
int n, d;
int g[200][3];
int dist[200];
int path[200];
int pos;
int level, num;
struct Canjump{
int pos;
int dis;
}canjump[200];
bool cmp(Canjump j1, Canjump j2)
{
return j1.dis<j2.dis;
}
typedef struct queue *Queue;
struct queue{
int *data;
int front, rear;
};
Queue createQueue(int size)
{
Queue Q = (Queue)malloc(sizeof(struct queue));
Q->data = (int *)malloc(sizeof(int)*size);
Q->front = -1;
Q->rear = -1;
return Q;
}
void AddQ(Queue Q, int x)
{
Q->data[++Q->rear] = x;
}
int DeleteQ(Queue Q)
{
return Q->data[++Q->front];
}
int IsEmpty(Queue Q)
{
if (Q->front == Q->rear)
return 1;
else
return 0;
}
int firstjump(int x)
{
double ju = sqrt(g[x][1]*g[x][1]+g[x][2]*g[x][2]);
if (ju<=7.5+d)
return ju;
else
return 0;
}
int issave(int x)
{
if ((g[x][1]-d<=-50)||(g[x][1]+d)>=50||(g[x][2]-d<=-50)||(g[x][2]+d)>=50)
return 1;
else
return 0;
}
int pan(int x, int y)
{
double ju = sqrt(x*x+y*y);
if (ju<=7.5)
return 0;
if (x<=-50||x>=50||y<=-50||y>=50)
return 0;
return 1;
}
int jump(int x, int y)
{
double ju = sqrt((g[x][1]-g[y][1])*(g[x][1]-g[y][1])+(g[x][2]-g[y][2])*(g[x][2]-g[y][2]));
if (ju<=d)
return 1;
else
return 0;
}
int find(int x)
{
Queue Q;
Q = createQueue(200);
AddQ(Q, x);
int answer = 0;
dist[x] = 0;
while (!IsEmpty(Q))
{
int V = DeleteQ(Q);
if (issave(V))
return V;
for (int i=1; i<=num; i++)
{
if (dist[i]==-1&&jump(i, V))
{
dist[i] = dist[V]+1;
path[i] = V;
AddQ(Q, i);
}
}
}
return answer;
}
void findpath(int x, int start)
{
if (x==start)
{
printf("%d %d\n", g[start][1], g[start][2]);
return ;
}
findpath(path[x], start);
printf("%d %d\n", g[x][1], g[x][2]);
}
int main()
{
scanf("%d%d", &n, &d);
if (d>=50)
{
printf("1\n");
return 0;
}
for (int i=1; i<=n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
if (pan(x, y))
{
num++;
g[num][1] = x;
g[num][2] = y;
}
}
for (int i=1; i<=num; i++)
{
int x = firstjump(i);
if (x)
{
++pos;
canjump[pos].pos = i;
canjump[pos].dis = x;
}
}
sort(canjump+1, canjump+1+pos, cmp);
int i;
for (i=1; i<=pos; i++)
{
memset(dist, -1, sizeof(dist));
memset(path, -1, sizeof(path));
int x = find(canjump[i].pos);
if (x!=0)
{
printf("%d\n", dist[x]+=2);
findpath(x, canjump[i].pos);
break;
}
}
if (i==pos+1)
printf("0");
return 0;
}