[SCOI2005]骑士精神(C++,启发式搜索)

news2024/9/30 11:32:45

题目描述

输入格式

第一行有一个正整数 T T T T ≤ 10 T \le 10 T10),表示一共有 T T T 组数据。

接下来有 T T T 5 × 5 5 \times 5 5×5 的矩阵,0 表示白色骑士,1 表示黑色骑士,* 表示空位。两组数据之间没有空行。

输出格式

对于每组数据都输出一行。如果能在 15 15 15 步以内(包括 15 15 15 步)到达目标状态,则输出步数,否则输出 -1

样例 #1

样例输入 #1

2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100

样例输出 #1

7
-1

提示

解题思路:

启发式搜索其实就是有预测的暴力搜索,接下来介绍一下怎么预测

估价函数:

对于题中问题,最优解是每次移动都能将一个骑士归位,但这往往不可能做到

通过估价函数计算当前最优解需要几步,如果最优解都会超出限制,那么其余方法均不可能做到

//估价函数
int evaluate() {
	int cnt = 0;
	for (int i = 1; i <= row; i++) {
		for (int j = 1; j <= column; j++) {
			if (map[i][j] != 2 && goal[i][j] != map[i][j]) {
				cnt++;
			}
		}
	}
	return cnt;
}

注意空格不需要累计,否则会出现一些问题,之后具体介绍会有什么问题

根据估价函数,启发搜索的大致思路如下

void ida_dfs(int step, const int max_step) {//step代表当前操作了几步
	//结束判断
	
	//递归主体
	for (/* 遍历每一种可能 */) {
		//前置操作
		
		if (step + 1 + evaluate() <= max_step)//预测
			ida_dfs(step + 1);
		//返回后操作
		
	}
}

还有要补充的一点就是在启发式搜索的时候,不要一次性把max_step的值提高到 15 15 15

那样会因为递归过深而TLE

最后,先给出AC代码,然后说明如果在估价的时候将空格也计入会怎么样

#include <iostream>
using namespace std;
const int row = 5;
const int column = 5;
const int max_step = 15;

const int goal[row + 1][column + 1] = {//目标图
	0,0,0,0,0,0,
	0,1,1,1,1,1,
	0,0,1,1,1,1,
	0,0,0,2,1,1,
	0,0,0,0,0,1,
	0,0,0,0,0,0
};
int map[row + 1][column + 1];//当前图
const int try_step[8][2] = {//尝试方向
	{1, 2},{1, -2},{-1, 2},{-1, -2},
	{2, 1},{2, -1},{-2, 1},{-2, -1}
};
int blank_x, blank_y, ans;


//交换函数
void swap(int& x, int& y) {
	int t = x;
	x = y;
	y = t;
}

//估价函数
int evaluate() {
	int cnt = 0;
	for (int i = 1; i <= row; i++) {
		for (int j = 1; j <= column; j++) {
			if (map[i][j] != 2 && goal[i][j] != map[i][j]) {
				cnt++;
			}
		}
	}
	return cnt;
}

//越界判断
inline bool is_safe(int x, int y) {
	return !(x <= 0 || x > row || y <= 0 || y > column);
}

//启发式搜索
void ida_dfs(int x, int y, const int max_step, int step) {
	//停止搜索
	if (step == max_step) {
		if (!evaluate())
			ans = 1;
		return;
	}

	for (int i = 0; i < 8; i++) {
		int t_x = x + try_step[i][0];
		int t_y = y + try_step[i][1];
		if (!is_safe(t_x, t_y)) continue;

		swap(map[x][y], map[t_x][t_y]);
		if (step + 1 + evaluate() <= max_step)//预测
			ida_dfs(t_x, t_y, max_step, step + 1);

		swap(map[x][y], map[t_x][t_y]);//回溯
	}
}

int main() {
	int n;
	cin >> n;
	char c;
	while (n--) {
		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= column; j++) {
				cin >> c;
				if (c == '*') map[i][j] = 2;
				else map[i][j] = c - '0';
				if (map[i][j] == 2) {
					blank_x = i;
					blank_y = j;
				}
			}
			cin.ignore();
		}

		ans = 0;
		for (int i = 0; i <= max_step; i++) {
			ida_dfs(blank_x, blank_y, i, 0);
			if (ans) {
				cout << i << endl;
				break;
			}
		}
		if (!ans) cout << -1 << endl;
	}
	return 0;
}

我们知道,估价函数的作用是用当前的最优解去判断搜索继续进行下去是否还有意义

当把空格计入时,试想如果最后还差一步就达到目标时,估价函数的返回值是什么

没错,是 2 2 2

这时候估价函数不是最优解了,因为其实我们可以一次归位两个元素:一个空格,一个骑士

那么再具体到输出上会出现什么问题呢

先看一看我们的启发式搜索得出结果的条件

//停止搜索
if (step == max_step) {
	if (!evaluate())
		ans = 1;
	return;
}

是要求step == max_step && evaluate() == 0

那么这时候我们向前回溯一步

if (step + 1 + evaluate() <= max_step)//预测
	ida_dfs(t_x, t_y, max_step, step + 1);

这里的step值为max_step - 1evaluate()的返回值为 0 0 0

似乎也没什么问题?

再回溯一步,来到上一层的此处

if (step + 1 + evaluate() <= max_step)//预测
	ida_dfs(t_x, t_y, max_step, step + 1);

这里的step值是max_step - 2evaluate()的返回值为 2 2 2

是不是发现了很严重的问题?这里的判断条件是不成立的,也就是说我们根本得不出搜索结果

所以在采用估价函数时一定要清楚函数返回值的意义,这篇题解到这里就结束啦=v=

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/370527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Node.js】详细记录express路由和中间件

Node.js路由的概念什么是路由Express中的路由路由的匹配过程路由的使用创建路由模块文件注册路由模块文件为路由模块添加前缀Express中间件Express中间件格式定义中间件函数定义全局生效的中间件函数中间件的作用定义多个全局中间件局部生效的中间件定义多个局部生效的中间件了…

Ae:使用代理

如果希望加快合成的预览或渲染速度&#xff0c;可考虑对素材使用代理 Proxy。虽然在 Ae 中&#xff0c;可以指定任何的静止图像或视频为代理&#xff0c;但一般情况下还是建议创建源素材的低分辨率版本来作为代理。对素材创建或指定代理后&#xff0c;可随意切换是否使用代理来…

物联网在医疗保健领域的5大创新应用

如今&#xff0c;物联网的发展越来越迅速&#xff0c;我们无法低估物联网在当今世界的重要性。大多数人每天都会使用到物联网设备。例如&#xff0c;当你使用智能手表来跟踪你的锻炼时&#xff0c;你就间接地使用了物联网的功能。由于物联网为世界带来了很多有效的帮助&#xf…

【涨薪技术】0到1学会性能测试 —— LR录制回放事务检查点

前言 上一次推文我们分享了性能测试分类和应用领域&#xff0c;今天带大家学习性能测试工作原理、事务、检查点&#xff01;后续文章都会系统分享干货&#xff0c;带大家从0到1学会性能测试&#xff0c;另外还有教程等同步资料&#xff0c;文末免费获取~ 01、LR工作原理 通常…

【原创】java+swing+mysql生肖星座查询系统设计与实现

今天我们来开发一个比较有趣的系统&#xff0c;根据生日查询生肖星座&#xff0c;输入生日&#xff0c;系统根据这个日期自动计算出生肖和星座信息反馈到界面。我们还是使用javaswingmysql去实现这样的一个系统。 功能分析&#xff1a; 生肖星座查询系统&#xff0c;顾名思义…

【uniapp微信小程序】跨平台使用echarts的方案选择踩坑

一、前言 使用Uniapp&#xff08;vue&#xff09;开发微信小程序&#xff0c;想用echarts图表实现类似github热力图的效果。 简要列一些可行或不可行的方案。 二、方案对比 1. 【应用】&#xff1a;微信小程序原生开发 有echarts官网提供的跨平台方案&#xff1a;在微信小程…

CHATGPT是新的“搜索引擎终结者”吗?百度是否慌了

ChatGPT 以其非凡的自然语言处理 &#xff08;NLP&#xff09; 能力和清晰的响应风靡全球&#xff0c;有望带来一场重大的技术革命。在不知不觉中&#xff0c;叙事转向了ChatGPT与百度的对决&#xff0c;因为来自OpenAI的智能和健谈的聊天机器人已经慢慢获得了“潜在的百度终结…

Allegro如何快速删除孤立铜皮操作指导

Allegro如何快速删除孤立铜皮操作指导 在做PCB设计的时候,铺铜是常用的设计方式,在PCB设计完成之后,需要删除PCB上孤立的铜皮,即铜皮有网络但是却没有任何连接 如下图 通过Status报表也可以看到Isolated shapes 如何快速地删除孤立铜皮,具体操作如下 点击Shape

C++ sort()函数和priority_queue容器中比较函数的区别

普通的queue是一种先进先出的数据结构&#xff0c;元素在队列尾追加&#xff0c;而从队列头删除。priority_queue中元素被赋予优先级。在创建的时候根据优先级进行了按照从大到小或者从小到大进行了自动排列&#xff08;大顶堆or小顶堆&#xff09;。可以以O(log n) 的效率查找…

23. 合并K个升序链表

解题思路&#xff1a;两种解法&#xff0c;一种优先级队列&#xff0c;一种分治优先级队列解法&#xff1a;以节点中存储的值进行排序依次遍历所有的链表&#xff0c;把链表中的节点加入到优先级队列中依次从优先级队列的弹出并删除最小的元素加入到新的链表中&#xff0c;直到…

final关键字是什么以及final的四种用法

final定义&#xff1a; final的翻译是最终&#xff0c;也就表示着它修饰的对象是最后一次被继承等含义。 被final修饰的对象不能更改其定义以及变量值 final的四种用法 一、修饰变量 public class Demo1 {public final int a 6;public void test() {a 10;} final修饰变量…

ESP-C3入门12. HTTPS请求、堆内存使用及JSON处理

ESP-C3入门12. HTTPS请求、堆内存使用及JSON处理一、创建HTTPS请求1. 基本流程2. ESP32 使用https证书的方式(1) 内置证书(2) ESP32管理证书3. 开发环境配置(1) 引用 esp-tls 库(2) 启用 CONFIG_MBEDTLS_CERTIFICATE_BUNDLE二、堆内存的使用1. 堆内存和栈内存2. 堆内存的使用(1…

Linux基础命令-which查找命令文件位置

文章目录 which 命令功能 语法格式 基本参数 参考实例 1&#xff09;查找chmod命令的文件位置 2&#xff09;查找chmod命令的所有路径 3&#xff09;一次性查找多个命令路径 4&#xff09;组合其他命令一起使用 5&#xff09;显示命令的版本信息 命令总结 which 命…

11 udp 发送数据的流程梳理

前言 呵呵 之前曾经看到过 湖光大佬 的 tcp 的流程梳理 呵呵 很高深 有很多不明白的地方, 不光是涉及到 linux 网络处理本身的东西, 还涉及到了 tcp协议 的一些具体的实现, 是非常的复杂 这里之前 在 0voice/linux_kernel_wiki 上面看到了网络协议栈部分的梳理 呵呵 自己也…

计算机网络(七):DNS协议和原理,DNS为什么用UDP,网页解析的全过程

文章目录一、什么是DNS二、DNS的作用三、DNS作用四、DNS为什么用UDP五、如果打开一个网站很慢&#xff0c;要如何排查六、网页解析的全过程一、什么是DNS DNS是域名系统的英文缩写&#xff0c;是一种组织成域层次结构的计算机和网络服务命名系统&#xff0c;用于TCP/IP网络。 …

数据库行业的 “叛逆者”:大数据已“死”,MotherDuck 当立

“大数据”已死——现今我们最重要的事情不是担心数据大小&#xff0c;而是专注于我们将如何使用它来做出更好的决策。数据库行业发展至今&#xff0c;在数据层面有很多的加速和变革&#xff0c;尤其是过去几年的云数仓爆炸式增长&#xff0c;带来了行业的很多变化。毫无疑问&a…

Fiddler报文分析-断点应用、模拟网络限速-HTTPS的 拦截

目录 一、报文分析 Statistics 请求性能数据 检查器&#xff08;Inspectors&#xff09; 自定义响应&#xff08;AutoResponder&#xff09; Composer Composer的功能就是用来创建HTTP Request然后发送请求。 允许自定义请求发送到服务器&#xff0c;即可以手动创建一个新…

Acwing---1242. 修改数组——并查集的简单应用

修改数组1.题目2.基本思想3.代码实现1.题目 给定一个长度为 N 的数组 A[ A1,A2,⋅⋅⋅AN ] &#xff0c;数组中有可能有重复出现的整数。 现在小明要按以下方法将其修改为没有重复整数的数组。 小明会依次修改 A2,A3,⋅⋅⋅,AN。 当修改 Ai 时&#xff0c;小明会检查 Ai 是…

在VScode里面添加Python解释器

VScode编辑器在安装好Python插件之后会自动选择环境变量中排序最高的那一个解释器作为默认解释器&#xff0c;而想要额外添加新的Python解释器就需要自己设置。 Python和VScode编辑器安装在Windows系统中 Python扩展插件安装在VScode编辑器 第一步&#xff0c;打开VScode编辑…

leaflet 绘制渐变折线(094)

第094个 点击查看专栏目录 本示例的目的是介绍如何在vue+leaflet中绘制渐变折线。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共89行)安装插件相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:htt…