BFS搜索算法应用_Codevs 1004

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cstring>
#include <map>
#include <set>
using namespace std;

const int maxn = 4;
//可移动方向
int dir[4][2] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
struct Status {
    //last = 1 : 黑子, last = 2 : 白子
    //包括把16位3进制转换成一个十进制数的结果hash,移动步数step
    int hash, step, last;      //hash:为了描述棋子的位置信息,但是不能重复
    int map[maxn][maxn];
} Map;

/*
* h[1][x]记录黑子放的移动到达的信息
* h[1][x]=false,表示还没有移动这个状态
* h[1][x]=true, 表示之前已经到达过, 不用进队
*/
map<int, bool> h[3];
queue<Status> que;                //BFS, 队列

void input();                            //输入数据
void solve();                            //启动函数
bool judge(int r, int c);        //判断越界
bool check(Status a);              //判断是否满足目标状态
//移动一步,生成新的棋子位置, k 为移动方向
void Move(Status now, int r, int c, int k);
void findSpace(const Status& now, int &r, int &c, int &r2, int &c2); //找到空格的位置
//把此时棋盘的状态, 全部用0,1,2表示每一位的三进制,转换成一个十进制
int getHash(Status a);          //对当前棋盘的棋子设置HashCode
void BFS();                              //宽搜BFS

void input()
{
    char s[10];
    /*
    * 把每一位的棋子 换成 空格-0,黑子-1, 白子-2 (三进制)
    * 这是一个16位的3进制数, 对应一个十进制数, 然后通过哈希该
    * 棋盘的十进制数, 则可找到对应的棋盘状态
    */
    for (int i = 0; i < maxn; i++)
    {
        scanf("%s", s);
        for (int j = 0; j < maxn; j++) {
            if (s[j] == ‘B‘) Map.map[i][j] = 1;
            if (s[j] == ‘W‘) Map.map[i][j] = 2;
        }
    }
}

bool judge(int r, int c)
{
    return (r >= 0 && r < maxn) && (c >= 0 && c < maxn);
}

bool check(Status a)
{
    bool flag = true;
    //横向连成4个
    for (int i = 0; i < maxn; i++)
    {
        flag = true;
        for (int j = 0; j < maxn - 1; j++) {
            if (a.map[i][j] != a.map[i][j + 1]) {
                flag = false;
            }
        }
        if (flag) return true;
    }

    //纵向连成4个
    for (int i = 0; i < maxn; i++)
    {
        flag = true;
        for (int j = 0; j < maxn - 1; j++) {
            if (a.map[j][i] != a.map[j + 1][i]) {
                flag = false;
            }
        }
        if (flag) return true;
    }

    flag = true;
    for (int i = 0; i < maxn - 1; i++) {
        if (a.map[i][i] != a.map[i + 1][i + 1]) {
            flag = false;
        }
    }
    if (flag) return true;

    flag = true;
    for (int i = maxn - 1; i > 0; i--) {
        if (a.map[i][i] != a.map[i - 1][i - 1]) {
            flag = false;
        }
    }
    if (flag) return true;

    //都没有连成4子, false
    return false;
}

//全部用0,1,2表示每一位的三进制,转换成一个十进制
//用了Hash查找
int getHash(Status a)
{
    int res = 0;
    int k = 1;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            res += a.map[i][j] * k;
            k *= 3;
        }
    }
    return res;
}

void findSpace(const Status& now, int &r1, int &c1, int &r2, int &c2)
{
    for (int i = 0; i < maxn; i++)
    {
        for (int j = 0; j < maxn; j++) {
            if (!now.map[i][j])
            {
                if (r1 == -1 && c1 == -1) {
                    r1 = i; c1 = j;
                }
                else {
                    r2 = i; c2 = j;
                }
            }
        }
    }
}

/*每移动 一步,都需要对其进行
* 1.是否越界检查
* 2.移动棋子, 并标志移动, 并设置下一次移动的棋子种类
* 3.是否完成目标检查
* 4.未完成 则 设置新棋盘的HashCode
* 5.检查该棋子状态 是否出现过, 没有则入队,并标志为出现过
*移动一步,生成新的棋子位置, k 为移动方向
*/
void Move(Status now, int r, int c, int k)
{
    Status tmp = now;
    int tmpx = r + dir[k][0];
    int tmpy = c + dir[k][1];
    //判断是否越界 || 先后手, 不能两次都移动自己的子
    //(如,第一次移动白子,第二次,白子能够移动还移动白子,是错误行为
    if (!judge(tmpx, tmpy) || tmp.map[tmpx][tmpy] == tmp.last)
        return;
    tmp.last = 3 - tmp.last;       //取反,上次白子(1), 这次就黑子(2)
    swap(tmp.map[tmpx][tmpy], tmp.map[r][c]);  //交换棋子和空白位置
    tmp.hash = getHash(tmp);       //重新设置hashCode
    tmp.step++;                              //移动成功,步数+1
    if (check(tmp)) {
        printf("%d\n", tmp.step);
        exit(0);                   //结束整个程序
    }
//表示tmp.last这个种类, 单独的某个棋子 当前的状态-是否移动过
    //false-没有移动过,可以入队
    if (!h[tmp.last][tmp.hash])
    {
        h[tmp.last][tmp.hash] = true;  //标志此状态已经出现过
                que.push(tmp);                                 //入队
    }
}

void BFS()
{
    Map.hash = getHash(Map);    //首状态棋盘对应的HashCode
    //因为谁先下都行,所以两个棋子都应该入队
        Map.last = 1;
    que.push(Map);
    Map.last = 2;  //黑
    que.push(Map);

    while (!que.empty())
    {
        Status now;
        now = que.front();
        que.pop();
        int r1 = -1, c1 = -1, r2 = -1, c2 = -1;
        findSpace(now, r1, c1, r2, c2);  //找到空格位置 

        //一个棋盘有两个空格,所以两个一起来搜索四个方向
         for (int k = 0; k < maxn; k++) {
            Move(now, r1, c1, k);
            Move(now, r2, c2, k);
        }
    }
}

void solve()
{
    input();
    BFS();
}

int main()
{
    solve();
    return 0;
}

BFS算法不错的练习~

参考了这篇博客: http://blog.csdn.net/re_cover/article/details/9034219

时间: 2024-10-12 09:58:15

BFS搜索算法应用_Codevs 1004的相关文章

BFS/DFS算法介绍与实现(转)

广度优先搜索(Breadth-First-Search)和深度优先搜索(Deep-First-Search)是搜索策略中最经常用到的两种方法,特别常用于图的搜索.其中有很多的算法都用到了这两种思想,比如:Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想.BFS的思想:从一个图的某一个顶点V0出发,首先访问和V0相邻的且未被访问过的顶点V1.V2.--Vn,然后依次访问与V1.V2--Vn相邻且未被访问的顶点.如此继续,找到所要找的顶点或者遍历完整个图.由此

搜索的题

1005 生日礼物 #include<algorithm> #include<cstdio> #include<iostream> using namespace std; int as[10][12],fs[12],sum[12],maxn=1001; int n,m; void dfs(int s) { for(int i=0;i<=fs[s];i++) { for(int k=1;k<=m;k++) sum[k]+=as[s][k]*i; if(s&l

剪枝算法(算法优化)

一:剪枝策略的寻找的方法 1)微观方法:从问题本身出发,发现剪枝条件 2)宏观方法:从整体出发,发现剪枝条件. 3)注意提高效率,这是关键,最重要的. 总之,剪枝策略,属于算法优化范畴:通常应用在DFS 和 BFS 搜索算法中:剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径. 二:剪枝算法(算法优化) 1.简介 在搜索算法中优化中,剪枝,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是剪去了搜索树中的某些"枝条",故称剪枝.应用剪枝优化的核心问题是设计剪枝判断方法,即确定

『ACM C++』HDU杭电OJ | 1415 - Jugs (灌水定理引申)

今天总算开学了,当了班长就是麻烦,明明自己没买书却要带着一波人去领书,那能怎么办呢,只能说我善人心肠哈哈哈,不过我脑子里突然浮起一个念头,大二还要不要继续当这个班委呢,既然已经体验过就可以适当放下了吧,用心在自己的研究上.晚上级会开完也就八点多了,开始打打题,今天在HDU杭电的ACM集训题看到一个奇葩的题,前来献上. 今日推荐: <全球风暴> 一部宇宙航空和地球气候片的良心佳作,后期特效建模都是特别杠杠的大片,不会让你失望的哟,我已经三刷了哈哈哈.这部片在爱奇艺有上线,有兴趣的朋友可以看看鸭.

PTA 1004 Counting Leaves (30)(30 分)(建树dfs或者bfs,未AC 段错误)

1004 Counting Leaves (30)(30 分) A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child. Input Each input file contains one test case. Each case starts with a line containing 0 < N < 10

BFS简单题套路_Codevs 1215 迷宫

BFS 简单题套路 1. 遇到迷宫之类的简单题,有什么行走方向的,先写下面的 声明 const int maxn = 20; struct Status { int r, c; Status(int r = 0, int c = 0) : r(r), c(c) {} // int DIR; }; int N; //迷宫数量 int W; //迷宫宽度 char map[maxn][maxn]; //地图 //方向 : 分别代表 上.右.下.左向量 int dir[4][2] = { {-1, 0

hdu 4751 Divide Groups bfs (2013 ACM/ICPC Asia Regional Nanjing Online 1004)

SDUST的训练赛 当时死磕这个水题3个小时,也无心去搞其他的 按照题意,转换成无向图,预处理去掉单向的边,然后判断剩下的图能否构成两个无向完全图(ps一个完全图也行或是一个完全图+一个孤点) 代码是赛后看的网上大神,所以转载过来了,dfs染色的时候很巧妙,巧妙的用到了就两个无向完全图 #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <qu

A*搜索算法的JAVA实现 解棋盘爵士游历问题 BFS

A knight moves on a chessboard two squares up, down, left, or right followed by one square in one of the two directions perpendicular to the first part of the move (i.e., the move is L-shaped). Suppose the knight is on an unbounded board at square (0

codevs 1004 四子连棋 BFS、hash判重

004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Input