ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

涂色游戏Flood-it!(IDA star算法) - HDU 4127

2020-11-23 20:03:34  阅读:217  来源: 互联网

标签:HDU star int ++ color depth flags 涂色 return


做题之前,可以先到下面这个网站玩一会游戏:

https://unixpapa.com/floodit/?sz=14&nc=6

游戏开发里面,比较常用的一个搜索算法是寻路算法,寻路算法里面用的最多的是A*算法以及很多优化的A*算法,对于只有4个方向的寻路算法,之前在网上见到有A*的位运算优化,性能非常高,1ms能处理上百个格子的地图寻路!很多MMORPG网络游戏都会应用这些算法,如果有兴趣做游戏的童鞋可以多关注下~

本文暂时不讲解A*算法,而是讲解另外一种搜索算法,也就是IDA*算法。

IDA*算法的具体名称是 Iterative Deepening A*, 由Korf1985年提出。该算法的最初目的是为了利用深度搜索的优势解决广度A*的空间问题,其代价是会产生重复搜索

IDA*算法最显著的特点是它有一个限制深度(max-depth),每次迭代都不会超过这个深度,另外和A*算法一样,也有一个评估函数用于剪枝。

学习IDA*最好的办法是先跟着看这道题的代码和注释然后再去理解,对于新手看IDA*的文字描述只会让你一脸懵逼。

题目就不翻译了,可以直接略过,题目要求的就是输入棋盘输出最少步数

Problem Description

Flood-it is a fascinating puzzle game on Google+ platform. The game interface is like follows:

At the beginning of the game, system will randomly generate an N×N square board and each grid of the board is painted by one of the six colors. The player starts from the top left corner. At each step, he/she selects a color and changes all the grids connected with the top left corner to that specific color. The statement “two grids are connected” means that there is a path between the certain two grids under condition that each pair of adjacent grids on this path is in the same color and shares an edge. In this way the player can flood areas of the board from the starting grid (top left corner) until all of the grids are in same color. The following figure shows the earliest steps of a 4×4 game (colors are labeled in 0 to 5):

Given a colored board at very beginning, please find the minimal number of steps to win the game (to change all the grids into a same color).

Input

The input contains no more than 20 test cases. For each test case, the first line contains a single integer N (2<=N<=8) indicating the size of game board.

The following N lines show an N×N matrix (\(a_{i,j}\))n×n representing the game board. \(a_{i,j}\) is in the range of 0 to 5 representing the color of the corresponding grid.
The input ends with N = 0.

Output

For each test case, output a single integer representing the minimal number of steps to win the game.

Sample Input

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

Sample Output

0
3

解题思路:

这道题用IDA*算法解还是很自然的,大概思路如下:

(1)输入棋盘;

(2)迭代限制最大深度,每次迭代执行过程;

(3)每次迭代清零标记;

(4)从位置(0,0)开始寻找颜色;

(5)通过DFS深度搜索迭代,依次尝试6种颜色,搜索该次迭代深度的可能解;

(6)一旦搜索到解,就是最优解~(因为有迭代加深的特性)

源代码:GCC 184ms

#include <stdio.h>
#include <string.h>

#define MAXN 8

int size;
int board[MAXN][MAXN];
int dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, { -1, 0} };
int flags[MAXN][MAXN];
int max_depth;

//更新棋盘的标记
void update_flags(int i, int j, int color)
{
    //如果当前位置颜色不同,则不用更新
    if (board[i][j] != color)
    {
        //标记为2
        flags[i][j] = 2;
        return;
    }

    //如果相同则标记为1
    flags[i][j] = 1;

    //4个方向
    for (int k = 0; k < 4; k++)
    {
        int x = i + dir[k][0];
        int y = j + dir[k][1];

        if (x < 0 || y < 0 || x >= size || y >= size || flags[x][y])
            continue;

        update_flags(x, y, color);
    }
}

//计算剩余的颜色数量
int color_count()
{
    int ret = 0;
    int s = 0;

    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            //如果标记不是相同颜色,位置1
            if (flags[i][j] != 1)
                s |= (1 << board[i][j]);
        }
    }

    //检查还有几种颜色
    while (s) {
        ret += s & 1;
        s >>= 1;
    }

    return ret;
}

int dfs(int depth)
{
    //如果颜色数量大于剩余步数,则行不通(评估函数)
    if (color_count() > max_depth - depth)
        return 0;

    //如果当前深度刚好等于最大深度,说明已经找完了
    if (depth == max_depth)
        return 1;

    int temp[MAXN][MAXN];
    int color_exist;

    //直接内存拷贝一份二维数组
    memcpy(temp, flags, sizeof(flags));

    //6种颜色
    for (int color = 0; color < 6; color++)
    {
        color_exist = 0;

        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                //当前位置是不同颜色且正好等于要搜索的颜色
                if (flags[i][j] == 2 && board[i][j] == color)
                {
                    //存在这种颜色
                    color_exist = 1;
                    update_flags(i, j, color);
                }
            }
        }

        //颜色不存在,继续搜索
        if (!color_exist)
            continue;
        //如果更新了棋盘,就深度搜索一下,如果成功就返回
        if (dfs(depth + 1))
            return 1;

        //内存拷贝一份二维数组,还原flags标记
        memcpy(flags, temp, sizeof(flags));
    }
    return 0;
}

void solved() {
    //输入棋盘
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++)
            scanf ("%d", &board[i][j]);
    }

    //限定最大深度
    for (max_depth = 0; ; max_depth++)
    {
        //flags清零
        memset(flags, 0, sizeof(flags));
        //更新棋盘
        update_flags(0, 0, board[0][0]);

        if (dfs(0))
            break;
    }

    printf ("%d\n", max_depth);
}

int main() {
    //freopen("test.txt", "r", stdin);

    while (scanf("%d", &size), size) {
        solved();
    }

    return 0;
}
// Cpp
// Author : RioTian
// Time : 20/11/23
#include <bits/stdc++.h>
#define ms(a, b) memset(a, b, sizeof(a))
#define mc(a, b) memcpy(a, b, sizeof(a))
using namespace std;
const int N = 8;
int Size;
int e[N][N];  //保存棋盘
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int flags[N][N];
int max_depth;

// (1)输入棋盘;

// (2)迭代限制最大深度,每次迭代执行过程;

// (3)每次迭代清零标记;

// (4)从位置(0,0)开始寻找颜色;

// (5)通过DFS深度搜索迭代,依次尝试6种颜色,搜索该次迭代深度的可能解;

// (6)一旦搜索到解,就是最优解~(因为有迭代加深的特性)

//更新棋盘的标记
void update_flags(int i, int j, int color) {
    //如果当前位置颜色不同,则不用更新
    if (e[i][j] != color) {
        //标记为2
        flags[i][j] = 2;
        return;
    }

    //如果相同则标记为1
    flags[i][j] = 1;

    // 4个方向
    for (int k = 0; k < 4; k++) {
        int x = i + dir[k][0];
        int y = j + dir[k][1];

        if (x < 0 || y < 0 || x >= Size || y >= Size || flags[x][y])
            continue;

        update_flags(x, y, color);
    }
}

//计算剩余的颜色数量
int color_count() {
    int ret = 0;
    int s = 0;

    for (int i = 0; i < Size; i++) {
        for (int j = 0; j < Size; j++) {
            //如果标记不是相同颜色,位置1
            if (flags[i][j] != 1)
                s |= (1 << e[i][j]);
        }
    }

    //检查还有几种颜色
    while (s) {
        ret += s & 1;
        s >>= 1;
    }

    return ret;
}

int dfs(int depth) {
    //如果颜色数量大于剩余步数,则行不通(评估函数)
    if (color_count() > max_depth - depth)
        return 0;

    //如果当前深度刚好等于最大深度,说明已经找完了
    if (depth == max_depth)
        return 1;

    int temp[N][N];
    int color_exist;

    //直接内存拷贝一份二维数组
    memcpy(temp, flags, sizeof(flags));

    // 6种颜色
    for (int color = 0; color < 6; color++) {
        color_exist = 0;

        for (int i = 0; i < Size; i++) {
            for (int j = 0; j < Size; j++) {
                //当前位置是不同颜色且正好等于要搜索的颜色
                if (flags[i][j] == 2 && e[i][j] == color) {
                    //存在这种颜色
                    color_exist = 1;
                    update_flags(i, j, color);
                }
            }
        }

        //颜色不存在,继续搜索
        if (!color_exist)
            continue;
        //如果更新了棋盘,就深度搜索一下,如果成功就返回
        if (dfs(depth + 1))
            return 1;

        //内存拷贝一份二维数组,还原flags标记
        memcpy(flags, temp, sizeof(flags));
    }
    return 0;
}

void solve() {
    //键入棋盘
    for (int i = 0; i < Size; ++i)
        for (int j = 0; j < Size; ++j)
            cin >> e[i][j];

    //限定最大深度
    for (max_depth = 0;; max_depth++) {
        // flags清零
        memset(flags, 0, sizeof(flags));
        //更新棋盘
        update_flags(0, 0, e[0][0]);

        if (dfs(0))
            break;
    }
    cout << max_depth << endl;
}
int main() {
    freopen("in.txt", "r", stdin);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    while (cin >> Size && Size)
        solve();
}

最后安利一下关于A*算法的介绍:here

本题文章参考:https://blog.csdn.net/weizhuwyzc000/article/details/47345573

标签:HDU,star,int,++,color,depth,flags,涂色,return
来源: https://www.cnblogs.com/RioTian/p/14026504.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有