图的搜索和最短路径-Saving James Bond

图的搜索-深度优先搜索DFS

  • 题目
    06-图2 Saving James Bond - Easy Version
  • 分析
    James从中心岛屿开始跳,这一跳需要进行特殊处理,然后在鳄鱼头上跳的时候,利用dfs进行搜索,一旦可以跳到安全区域就结束搜索。
    注意中心岛屿并不是P[0]。
  • 代码
#include<stdio.h>
#include<math.h>

#define maxn 101

int N,D;
int visited[maxn];
int flag;

struct point{
    int x;
    int y;
}P[maxn];

//求某个点与原点的距离的平方
double distance1(int i)
{
    return P[i].x * P[i].x + P[i].y * P[i].y;
}
//求某两个点之间的距离的平方
double distance2(i, j)
{
    return ((P[i].x-P[j].x)*(P[i].x-P[j].x) + (P[i].y-P[j].y)*(P[i].y-P[j].y));
}

int canSave(int i)
{
    if(P[i].x-D <= -50 || P[i].x+D >= 50 || P[i].y-D <= -50 || P[i].y+D >= 50)
        return 1;
    return 0;
}

void dfs(int i){
    //printf("%d\n",i);
    visited[i] = 1;
    if(canSave(i)){
        flag = 1;
        return;
    }else{
        int j;
        for(j=0; j<N; j++){
            if(!visited[j] && distance2(i,j)<=D*D){
                dfs(j);
            }
            if(flag)    break; 
        }
    }   
}

int main()
{
    flag = 0;
    #ifndef ONLINE_JUDGE
    freopen("save1.txt","r",stdin);
    #endif

    int i;
    scanf("%d%d", &N,&D);
    for(i=0; i<N; i++){
        scanf("%d%d", &P[i].x, &P[i].y);
        visited[i] = 0;
    }

    if(7.5+D >= 50) flag = 1;

    if(!flag){
        for(i=0; i<N; i++){
            if(!visited[i] && (7.5+D)*(7.5+D)>=distance1(i)){
                dfs(i);
            }
            if(flag)    break;      
        }
    }

    if(flag){
        printf("Yes\n");
    }else{
        printf("No\n");
    }

    return 0;
}

图的最短路径

  • 题目
    07-图5 Saving James Bond - Hard Version (30分)
  • 分析
    这道题是求一个单源无向无权重的图的最短路径问题,但不是普通意义上的最短路径,一般的最短路径是求一个顶点到其余各个顶点的最短路径,而这道题是求从中心点到跳出边缘的最短路径。
    需要注意的是:一是求最少跳数的最短路(bfs搜索,同时记录跳数)。二是要保存最短路径(用一个path[]数组来保存),三是当跳数相同时,最短路选择第一跳最短的那个路径(可以先根据第一跳的长度来排序)。
    上面这样做的话,其实找到的第一个可以跳出去的点,它的深度就是最短的跳数,此时就可以输出了。因为本身就是按照广度优先算法,第一个满足的点就是深度最小的。
  • 我的代码
#include<iostream>
#include<algorithm>
#include<stack> 
#include<queue>
using namespace std;
#define maxn 101


int N,D;
int dist[maxn];//P[0]表示原点,dist[i]表示P[i]到原点的最短距离 
int path[maxn];//path[i]表示到P[0]的路上经过的顶点 
int flag;
int minPath = maxn;
queue<int> Q;
stack<int> S;

struct point{
    int x;
    int y;
}P[maxn];

double distance1(int i)
{
    return P[i].x * P[i].x + P[i].y * P[i].y;
}
double distance2(int i,int j)
{
    return ((P[i].x-P[j].x)*(P[i].x-P[j].x) + (P[i].y-P[j].y)*(P[i].y-P[j].y));
}

int canSave(int i)
{
    if(P[i].x-D <= -50 || P[i].x+D >= 50 || P[i].y-D <= -50 || P[i].y+D >= 50)
        return 1;
    return 0;
}

int comp(const point &a, const point &b)
{
    if( (a.x * a.x + a.y * a.y) < (b.x * b.x + b.y * b.y))  return 1;
    return 0;
}

int BFS()
{
    int tmpPath = 1,i;
    for(i=1; i<=N; i++){
        if(dist[i]==-1 && (7.5+D)*(7.5+D)>=distance1(i)){
            Q.push(i);
            dist[i] = 2;
            //printf("%d\n", i);
        }   
    }
    while(!Q.empty()){
        int tmp = Q.front();
        Q.pop();

        if(canSave(tmp)){
            flag = 1;
            minPath = dist[tmp];
            int k;
            for(k=0; k<minPath-1; k++){
                S.push(tmp);
                tmp = path[tmp];
            }
            break;
        }

        for(i=1; i<=N; i++){
            if(dist[i]==-1 && distance2(tmp,i)<=D*D ){
                dist[i] = dist[tmp] + 1;
                path[i] = tmp;
                Q.push(i);
            }
        }
    }
}
int main()
{
    flag = 0;
    #ifndef ONLINE_JUDGE
    freopen("save2.txt","r",stdin);
    #endif


    int i;
    scanf("%d%d", &N,&D);
    for(i=1; i<=N; i++){
        scanf("%d%d", &P[i].x, &P[i].y);
        //visited[i] = 0;
    }
    sort(P+1, P+N+1, comp); //排序 
    for(i=1; i<=N; i++){
        dist[i] = -1;
        path[i] = -1;
    }

    if(7.5+D >= 50){
        printf("1\n");
        return 0;
    }

    BFS();

    if(flag){
        printf("%d\n",minPath);
        for(i=0; i<minPath-1; i++){
            int tmp;
            tmp = S.top();
            S.pop();
            printf("%d %d\n", P[tmp].x, P[tmp].y);
        }
    }else{
        printf("0\n");
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值