涂色游戏Flood-it!(IDA star算法) - HDU 4127
做题之前,可以先到下面这个网站玩一会游戏:
https://unixpapa.com/floodit/?sz=14&nc=6
游戏开发里面,比较常用的一个搜索算法是寻路算法,寻路算法里面用的最多的是A*算法以及很多优化的A*算法,对于只有4个方向的寻路算法,之前在网上见到有A*的位运算优化,性能非常高,1ms能处理上百个格子的地图寻路!很多MMORPG网络游戏都会应用这些算法,如果有兴趣做游戏的童鞋可以多关注下~
本文暂时不讲解A*算法,而是讲解另外一种搜索算法,也就是IDA*算法。
IDA*算法的具体名称是 Iterative Deepening A*, 由Korf在1985年提出。该算法的最初目的是为了利用深度搜索的优势解决广度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
涂色游戏Flood-it!(IDA star算法) - HDU 4127的更多相关文章
- hdu 4559 涂色游戏(SG)
在一个2*N的格子上,Alice和Bob又开始了新游戏之旅. 这些格子中的一些已经被涂过色,Alice和Bob轮流在这些格子里进行涂色操作,使用两种涂色工具,第一种可以涂色任意一个格子,第二种可以涂色 ...
- NOIp十连测 涂色游戏
[问题描述]小A 和小B 在做游戏.他们找到了一个n 行m 列呈网格状的画板.小A 拿出了p 支不同颜色的画笔,开始在上面涂色.看到小A 涂好的画板,小B 觉得颜色太单调了,于是把画板擦干净,希望涂上 ...
- [CSP-S模拟测试]:涂色游戏(DP+组合数+矩阵快速幂)
题目描述 小$A$和小$B$在做游戏.他们找到了一个$n$行$m$列呈网格状的画板.小$A$拿出了$p$支不同颜色的画笔,开始在上面涂色.看到小$A$涂好的画板,小$B$觉得颜色太单调了,于是把画板擦 ...
- hdu 4559 涂色游戏(对SG函数的深入理解,推导打SG表)
提议分析: 1 <= N <= 4747 很明显应该不会有规律的,打表发现真没有 按题意应该分成两种情况考虑,然后求其异或(SG函数性质) (1)找出单独的一个(一列中只有一个) (2)找 ...
- LYDSY模拟赛day3 涂色游戏
/* 非常好的题 */ #include <cstdio> #include <iostream> #include <cstdlib> #include < ...
- 联赛模拟测试5 涂色游戏 矩阵优化DP
题目描述 分析 定义出\(dp[i][j]\)为第\(i\)列涂\(j\)种颜色的方案数 然后我们要解决几个问题 首先是求出某一列涂恰好\(i\)种颜色的方案数\(d[i]\) 如果没有限制必须涂\( ...
- 【矩阵乘优化DP】涂色游戏
题目大意 用 \(p\) 种颜色填 \(n\times m\) 的画板,要求任意相邻两列的颜色数都不少于 \(q\) ,求方案数. 数据范围 \(1\leq n\leq 100,1\leq m\leq ...
- hdu 4559 涂色游戏 博弈论
构造SG函数:sg[i]表示2*i的sg值!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm ...
- [NOI Online #2 提高组]涂色游戏 题解
题目描述 你有 1020 个格子,它们从 0 开始编号,初始时所有格子都还未染色,现在你按如下规则对它们染色: 编号是 p1 倍数的格子(包括 0号格子,下同)染成红色. 编号是 p2 倍数的格子染成 ...
- 算法习题---4-4骰子涂色(UVa253)
一:题目 分别对两个骰子的六个面涂色r-红 b-蓝 g-绿,通过转动骰子,看两个骰子是不是一样的涂色方法 (一)题目详解 题目规定了正方体的六个面的序号:从1-,按照这个需要提供涂色序列 (二)案例展 ...
随机推荐
- 【Javaweb】servlet七 | 解决post请求中文乱码问题
问题描述 在get请求时(可以接收) post请求时(出现了中文乱码问题) 解决方案 在doPost函数中添加如下代码 // 设置请求体字符为UTF-8,从而解决post请求的中文乱码问题// 也要在 ...
- mySql中使用命令行建表基本操作
一:打开命令行启动mysql服务 注意事项:应该使用管理员身份打开命令行键入命令:net start mysql (鼠标右键使用管理员身份打开),否则会出现拒绝访问报错. 二:登陆数据库 登陆命令为& ...
- Mock基础知识
使用的框架:moco框架下载地址:https://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/1.1.0/ 启动方式:java -j ...
- 浅谈SQL优化小技巧
回顾MySQL的执行过程,帮助介绍如何进行sql优化. (1)客户端发送一条查询语句到服务器: (2)服务器先查询缓存,如果命中缓存,则立即返回存储在缓存中的数据: (3)未命中缓存后,MySQL通过 ...
- [GDOIpj222A] 点指兵兵
第一题 点指兵兵 提交文件: bing.cpp 输入文件: bing.in 输出文件: bing.out 时间空间限制: 1 秒, 256 MB 你一定有过在两个物品之间犹豫不决的时候,想要借助一些方 ...
- 精致的Javascript代码
1. 统计一个数组中,每个值的个数 var cards = [1, 2, 3, 4, 3, 2, 1, 4, 5] var dict = {}; for(var i = 0; i < cards ...
- 记一次 .NET某股票交易软件 灵异崩溃分析
一:背景 1. 讲故事 在dump分析的旅程中也会碰到一些让我无法解释的灵异现象,追过这个系列的朋友应该知道,上一篇我聊过 宇宙射线 导致的程序崩溃,后来我又发现了一例,而这一例恰恰是高铁的 列控连锁 ...
- elasticsearch oom问题分析
背景 线上发现elasticsearch集群状态red,并且有个es节点jvm内存使用不断升高,直到gc后依然内存不够使用,服务停止.查看日志,elasticsearch出现OOM报错. [2023- ...
- 斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 01.基础AI与行为树
斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 前言&摘要 本篇文章是基于斯坦福UE4 C++课程的学习记录.因为B站用户surkea由于学业原因,暂停了课程 ...
- 简易机器学习笔记(十一)opencv 简易使用-人脸识别、分类任务
前言 前段时间摸了下机器学习,然后我发现其实openCV还是一个很浩瀚的库的,现在也正在写一篇有关yolo的博客,不过感觉理论偏多,所以在学yolo之前先摸一下opencv,简单先写个项目感受感受op ...