【算法学习笔记】63. BFS SJTU OJ 1281 蹦蹦跳跳

典型的BFS,找到起点直接进行搜搜即可。要注意的就是层数的处理。坐标到id的转换。还有就是要尽早判断是否达到终点。

代码注释很详细,最后面两个函数是一开始写的 用抽取邻接矩阵+Dijkstra 来算的,很麻烦 头脑一热的结果。。

#include <vector>
#include <queue>
#include <iostream>
using namespace std;

int map[31][31]={0};

int M,N,M1,M2;

struct Point
{
    int x;
    int y;
    int lay;//层数 用来计算结果
};
Point s;//起点
Point e;//终点

int Graph[31*31][31*31]={0};

inline int getID(int x,int y){
    if(x<=M and x>=1  and y>=1 and y<=N){
        if(map[x][y]!=0 and map[x][y]!=2)//不是水和沼泽才返回
            return (x-1) * N + y;
    }
    return -1;
}

inline void getPoint(int id, int& x,int& y){
    y = id % N;
    if(y==0)
        y = N;
    x = id / N ;
}

void init(){
    cin>>M>>N>>M1>>M2;
    for (int i = 1; i <= M; ++i)
    {
        for (int j = 1; j <= N; ++j)
        {
            cin>>map[i][j];
            if(map[i][j]==3){
                s.x = i;
                s.y = j;
            }else if(map[i][j]==4){
                e.x = i;
                e.y = j;
            }
        }
    }
}

int bfs(){
    //八个方向
    int dx[8] = {M1,M1,-M1,-M1,M2,M2,-M2,-M2};
    int dy[8] = {M2,-M2,M2,-M2,M1,-M1,M1,-M1};

    queue<Point> q;//BFS的队列
    s.lay = 0;//表示层数
    q.push(s);
    bool vis[31*31] = {0};
    int res=0;
    while(!q.empty()){
        Point cur = q.front();
        if(cur.x == e.x and cur.y == e.y)//其实这步没必要..早期代码遗留
            break;
        q.pop();
        res = cur.lay;
        vis[getID(cur.x,cur.y)] = true; //访问状态更改
        for (int i = 0; i < 8; ++i)
        {
            int x = cur.x + dx[i];
            int y = cur.y + dy[i];
            int newid = getID(x,y);
            if(newid!=-1 and !vis[newid]){
                Point p;
                p.x = x ;
                p.y = y;
                p.lay = cur.lay + 1;
                if(x==e.x and y==e.y)//找到终点了
                    return p.lay;
                q.push(p);
                vis[newid] = true;//访问状态更改
            }
        }
    }

    return res;
}

int main(int argc, char const *argv[])
{

    //最短路径问题
    init();

    //另外一种方法就是抽取邻接矩阵 然后运用最短路径d算法
       //buildAdjMap();
    //cout<<dijkstra()<<endl;

    cout<<bfs()<<endl;

    return 0;
}

void buildAdjMap(){//构造邻接矩阵
    int dx[8] = {M1,M1,-M1,-M1,M2,M2,-M2,-M2};
    int dy[8] = {M2,-M2,M2,-M2,M1,-M1,M1,-M1};

    for (int i = 1; i <= M; ++i){
        for (int j=1; j <= N; ++j){
            int x,y;
            int fromID = getID(i,j);
            for(int k = 0; k < 8 ; ++k){//遍历8个方向
                x = i + dx[k];
                y = j + dy[k];
                int endID = getID(x,y);
                if(endID != -1){
                    Graph[fromID][endID]=1;
                    Graph[endID][fromID]=1;//无向图
                }
            }
        }
    }

}

int dijkstra(){//最短路径算法 写的太麻烦了 主要是想试试好不好使
    int res = 0;
    int cnt = M*N;//总点数目
    int begin = getID(s.x, s.y);//起点
    int end = getID(e.x, e.y);//终点
    const int INF = 9999999;
    int D[31*31];//存储临时距离
    for (int i = 1; i <= cnt; ++i)
        D[i] = Graph[begin][i] > 0 ? Graph[begin][i] : INF;

    D[begin] = 0;

    int S[31*31],Q[31*31];//无所谓

    int p_S=0 ,p_Q=0, len_S = 1 , len_Q = cnt-1 ;
    S[p_S++] = begin;
    for (int i = 1; i <= cnt; ++i) if( i != begin)
    {
        Q[p_Q++] = i;
    }

    while(len_Q > 1){
        int u=0, minD = INF;
        int qid = 0;
        for (int i = 0; i < p_Q; ++i) if(Q[i]!=0)
        {
            if(D[Q[i]]<minD){
                u = Q[i];
                minD = D[u];
                qid = i;
            }
        }
        if(u ==0 or u == end){
            break;
        }
        Q[qid] = 0; len_Q--;
        S[p_S++] = u; len_S++;

        for (int i = 0; i < p_Q; ++i) if(Q[i]!=0)
        {
            int v = Q[i];
            if(Graph[u][v] > 0){
                if(D[v] > D[u]+Graph[u][v])
                    D[v] = D[u]+Graph[u][v];//更新
            }
        }

    }

    return D[end];
}
/*

 4 5 1 2

 1 0 1 0 1
 3 0 2 0 4
 0 1 2 0 0
 0 0 0 1 0

 1 -1 3 -1 5
 6 -1 -1 -1 10
 -1 12 -1 -1 -1
 -1 -1 -1 19 -1 

 */
时间: 2024-10-11 12:14:32

【算法学习笔记】63. BFS SJTU OJ 1281 蹦蹦跳跳的相关文章

带花树算法学习笔记

带花树算法学习笔记 难得yyb写了一个这么正式的标题 Q:为啥要学带花树这种东西啊? A:因为我太菜了,要多学点东西才能不被吊打 Q:为啥要学带花树这种东西啊? A:因为我做自己的专题做不动了,只能先去"预习"ppl的专题了 Q:为啥要学带花树这种东西啊? A:因为可以用来做题啊,比如某WC题目 先推荐一个很皮很皮的带花树讲解: 戳这里嗷 QaQ 言归正传 带花树的算法用来解决一般图的最大匹配问题 说起来,是不是想起来网络流里面的最小路径覆盖? 或者二分图的最大匹配的问题? 的确,带花

算法学习笔记 递归之 快速幂、斐波那契矩阵加速

递归的定义 原文地址为:http://blog.csdn.net/thisinnocence 递归和迭代是编程中最为常用的基本技巧,而且递归常常比迭代更为简洁和强大.它的定义就是:直接或间接调用自身.经典问题有:幂运算.阶乘.组合数.斐波那契数列.汉诺塔等.其算法思想: 原问题可分解子问题(必要条件): 原与分解后的子问题相似(递归方程): 分解次数有限(子问题有穷): 最终问题可直接解决(递归边界): 对于递归的应用与优化,直接递归时要预估时空复杂度,以免出现用时过长或者栈溢出.优化递归就是以

EM算法学习笔记2:深入理解

文章<EM算法学习笔记1:简介>中介绍了EM算法的主要思路和流程,我们知道EM算法通过迭代的方法,最后得到最大似然问题的一个局部最优解.本文介绍标准EM算法背后的原理. 我们有样本集X,隐变量Z,模型参数θ,注意他们3个都是向量,要求解的log似然函数是lnp(X|θ),而这个log似然函数难以求解,我们假设隐变量Z已知,发现lnp(X,Z|θ) 的最大似然容易求解. 有一天,人们发现引入任意一个关于隐变量的分布q(Z),对于这个log似然函数,存在这样一个分解: lnp(X|θ)=L(q,θ

算法学习笔记 KMP算法之 next 数组详解

最近回顾了下字符串匹配 KMP 算法,相对于朴素匹配算法,KMP算法核心改进就在于:待匹配串指针 i 不发生回溯,模式串指针 j 跳转到 next[j],即变为了 j = next[j]. 由此时间复杂度由朴素匹配的 O(m*n) 降到了 O(m+n), 其中模式串长度 m, 待匹配文本串长 n. 其中,比较难理解的地方就是 next 数组的求法.next 数组的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀,也可看作有限状态自动机的状态,而且从自动机的角度反而更容易推导一些. "前

算法学习笔记 最短路

图论中一个经典问题就是求最短路,最为基础和最为经典的算法莫过于 Dijkstra 和 Floyd 算法,一个是贪心算法,一个是动态规划,这也是算法中的两大经典代表.用一个简单图在纸上一步一步演算,也是很好理解的,理解透自己多默写几次即可记住,机试时主要的工作往往就是快速构造邻接矩阵了. 对于平时的练习,一个很厉害的 ACMer  @BenLin_BLY 说:"刷水题可以加快我们编程的速度,做经典则可以让我们触类旁通,初期如果遇见很多编不出,不妨就写伪代码,理思路,在纸上进行整体分析和一步步的演算

[算法学习笔记]直接插入排序笔记

直接插入排序概念: 带排元素放在elem[0...n-1]中,初始化时,elem[0]自成1个有序区,无序区为elem[1...n-1],从i=1起,到i=n-1,依次将elem[i]插入有序区[0...n-1]中 直接插入排序算法步骤: 1.在当前有序区域R[1,i-1]中查找R[i]的正确插入位置K(1<=K<=i-1) 2.将R[K,i-1]中的记录均向后移动 3.移动后腾出K位置,插入R[i] (最坏)时间复杂度:O(n^2) 空间复杂度:O(1) /// <summary>

八大排序算法学习笔记:冒泡排序

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 算法原理: 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. 针对所有

由LCS到编辑距离—动态规划入门—算法学习笔记

一切计算机问题,解决方法可以归结为两类:分治和封装.分治是减层,封装是加层. 动态规划问题同样可以用这种思路,分治. 它可以划分为多个子问题解决,那这样是不是用简单的递归就完成了?也许是的,但是这样会涉及太多的不便的操作.因为子问题有重叠! 针对这种子问题有重叠的情况的解决,就是提高效率的关键. 所以动态规划问题可以总结为:最优子结构和重叠子问题. 解决这个子问题的方式的关键就是:memoization,备忘录. 动态规划算法分以下4个步骤: 描述最优解的结构 递归定义最优解的值 按自底向上的方

八大排序算法学习笔记:插入排序(一)

插入排序     包括:直接插入排序,二分插入排序(又称折半插入排序),链表插入排序,希尔排序(又称缩小增量排序).属于稳定排序的一种(通俗地讲,就是两个相等的数不会交换位置) . 直接插入排序: 1.算法的伪代码(这样便于理解):     INSERTION-SORT (A, n)             A[1 . . n] for j ←2 to n do key ← A[ j] i ← j – 1 while i > 0 and A[i] > key do A[i+1] ← A[i]