zoukankan      html  css  js  c++  java
  • 洛谷 P1443 马的遍历

    嗯....

    这道题是一个标准的bfs,只要背过了bfs 的模板,这道题小菜一碟...

    首先先看题目:

    题目描述

    有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步

    输入输出格式

    输入格式:

     

    一行四个数据,棋盘的大小和马的坐标

     

    输出格式:

     

    一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)

     

    输入输出样例

    输入样例#1:
    3 3 1 1
    
    输出样例#1:
    0    3    2    
    3    -1   1    
    2    1    4    


    首先先讲一下思路:

    首先 bfs 肯定要用队列,两个队列分别存点的横、纵坐标,然后用nx和my两个数组分别存储马下一步能到达的方向,vis数组判断是否访问,
    g数组存棋盘,马每到一个点,首先将vis变为1,并且将横、纵坐标入队,然后进行bfs,将能一步到达的点储存,并且判断它是否越界,
    然后是否将其入队,最后输出结果即可...


    能想到用nx和ny两个数组来存储马前进的方向是此题的重点,能背过 bfs 的模板是此题前提与关键




    下面是AC代码,外加解析:


     1 #include<cstdio>
     2 //#include<iomanip>
     3 #include<iostream>
     4 #include<queue>
     5 #include<cstring>
     6 
     7 using namespace std;
     8 
     9 int g[401][401];//存棋盘 
    10 
    11 queue <int> q, q1;//q队列存横坐标,q1队列存纵坐标 
    12 
    13 int nx[8] = {1,2,2,1,-1,-2,-2,-1};//表示马横坐标的八种变化 
    14 int my[8] = {2,1,-1,-2,-2,-1,1,2};//表示马纵坐标的八种变化,为此题的重点
    15 bool vis[401][401]; //是否访问 
    16 
    17 int main(){
    18     int n, m;
    19     int x, y;
    20     memset(g,-1,sizeof(g));//初始化棋盘 
    21     scanf("%d%d",&n,&m);
    22     scanf("%d%d",&x,&y);
    23     g[x][y] = 0; 
    24     vis[x][y] = 1; 
    25     q.push(x);
    26     q1.push(y);
    27     // 开始进行 bfs,此题的框架
    28     while (!q.empty() ){
    29         int u = q.front();//将先前一个马的位置存储下来 
    30         int v = q1.front();
    31         q.pop();
    32         q1.pop();
    33         for(int i = 0; i <= 7; i++){
    34             int x1 = u + nx[i];//更新马的位置 
    35             int y1 = v + my[i];
    36             if (x1 > 0 && x1 <= n && y1 > 0 && y1 <= m && vis[x1][y1] == 0)//判断是否越界和是否被访问过 
    37              {
    38                 vis[x1][y1] = 1;
    39                 g[x1][y1] = g[u][v] + 1;// 到达此点的步数等于到达上一个点的步数加一 
    40                 q.push(x1); //将新的位置入队 
    41                 q1.push(y1);
    42             }    
    43         }
    44     }
    45     for(int i = 1; i <= n; i++){
    46         for(int j = 1; j <= m; j++){
    47             printf("%-5d",g[i][j]);
    48             //cout<<left<<setw(5)<<g[i][j];
    49         }
    50         printf("
    ");
    51     }
    52     return 0;
    53 }

    在这道题中,最终的输出方式与往常不同,请见下:

    左对齐宽5格可以有两种输出方法:

      

      1.使用printf:
        (1)对齐:
        printf中的左对齐表示为在%后加-
        printf中的右对齐表示为在%后加+
        (2)宽x格:(x为数)
        printf中的宽x格表示为在对齐符号后加x

      

        2.使用cout:

        (1)对齐:
        cout中的左对齐为在要输出的数之前加 <<left<<
        cout中的右对齐为在要输出的数之前加 <<right<<
        (2)宽x格:(x为数)
        cout中的宽x格为只需在对齐操作和要输出的数之间加 <<setw(x)<<

    注意:
    cout中的操作简单,但比较慢,并且在使用cout做上述操作时,需要加头文件 <iomanip> 

  • 相关阅读:
    sql server 删除重复数据新思路
    sqlserver 迁移 mysql
    ASP.NET Web deployment task failed. 请与服务器管理员联系,检查授权和委派设置 部署任务失败的解决方案
    数据库交互之减少IO次数
    sqlserver 安全设置
    windows设置相对路径的快捷方式
    利用SignalR实现实时推送信息
    image magick 备忘
    dotnetCore开发中遇到的一些问题
    “NETSDK1061: 项目是使用 Microsoft.NETCore.App 版本 2.1.14 还原的, 但使用当前设置, 将改用版本 2.1.0。”的处理方法
  • 原文地址:https://www.cnblogs.com/New-ljx/p/10416324.html
Copyright © 2011-2022 走看看