P1379 八数码难题

题目描述

在 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格,空格用 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式

输入初始状态,一行九个数字,空格用 0 表示。

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数。保证测试数据中无特殊无法到达目标状态数据。

输入输出样例

输入 #1复制

283104765

输出 #1复制

4

说明/提示

样例解释

图中标有 0 的是空格。绿色格子是空格所在位置,橙色格子是下一步可以移动到空格的位置。如图所示,用四步可以达到目标状态。

并且可以证明,不存在更优的策略。

解析:

1.最短步骤想到使用bfs,用string来记录当前的状态,遍历状态。

注意:string 下角标是从0开始的,x = dx/3 , y = dy%3; 为真实九宫格的坐标。九宫格坐标是从(0,0)开始的。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<unordered_map>
using namespace std;
unordered_map<string,int> d;
queue<string> q;
int dx[4] ={-1,0,1,0};
int dy[4] = {0,1,0,-1};

int bfs(string str)
{
	q.push(str);
	string end="123804765";
	while(q.size())
	{
		string s = q.front();
		q.pop();
		if(s==end) return d[s];
		int k = s.find('0');
		int x = k/3,y = k%3;
		for(int i = 0;i < 4;i++)
		{
			int a = x+dx[i],b = y + dy[i];
			if(a<0||a>=3||b<0||b>=3) continue;
			int dis = d[s];
			swap(s[k],s[a*3 + b]);
			if(!d.count(s))//交换 
				d[s] = dis+1,q.push(s);
			swap(s[k],s[a*3+b]);//还原			
		}
	}	
} 
int main()
{
	string s;
	cin >> s;
	cout << bfs(s)<<endl;	
	return 0;
}

时间复杂度为:O(9^{2})

使用A*算法进行优化。

A算法给出了评价函数的定义: f(n) = g(n) + h(n)
其中,n为待评价的节点;g(n)为从初始节点s到节点n的最佳路径耗散值的估计值;h(n)为从节点n到目标节点t的最佳路径耗散值的估计值,称为启发函数;f(n)为从初始节点s经过节点n到达目标节点的最佳路径耗散值的估计值,成为评价函数,我们每次从叶节点选出f(n)最小的节点扩展。
 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<unordered_map>
#include<bits/stdc++.h>
using namespace std;
unordered_map<string,int> d;
string goal = "123804765";
int gx[] = {-1,0,0,0,1,2,2,2,1};
int gy[] = {-1,0,1,2,2,2,1,0,0};
int dx[4] ={-1,0,1,0};
int dy[4] = {0,1,0,-1};
int f(string s)
{ // 每个数字到目的地的坐标 
	int res = 0;
	for(int i = 0;i < 9;i++)
	{
		int t = s[i]-'0';
		if(t) res+= abs(i/3 - gx[t]) + abs(i%3-gy[t]);
	}
	return res;
}
int bfs(string str)
{
	unordered_map<string,int> d;
	priority_queue<pair<int,string>> q;//默认大根堆 ,我们只需要取负数,小的数就会在上面 
	q.push({-f(str),str});
	d[str] = 0;
	while(q.size())
	{
		auto a = q.top();
		q.pop();
		string s = a.second;
		if(s== goal) return d[s]; // d 记录现实的 状态 f为理想状态下 曼哈顿距离 
		int k = s.find('0');
		int x = k /3,y = k%3;
		for(int i = 0;i < 4;i++)
		{
			int a = x+dx[i],b = y + dy[i];
			if(a<0|| a>=3||b<0|| b>=3) continue;
			string t = s;
			swap(t[k],t[a*3+b]);
			if(!d.count(t))
			{
				d[t] = d[s]+1,q.push({-(d[t] + f(t)),t});
			}
		}
	}
} 
int main()
{
	string s;
	cin >> s;
	cout << bfs(s)<<endl;	
	return 0;
}

相关推荐

  1. 洛谷 P1179 [NOIP2010 普及组] 数字统计

    2024-01-13 18:54:03       13 阅读
  2. 43.139.152.26 P2315 分数计算

    2024-01-13 18:54:03       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-13 18:54:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-13 18:54:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-13 18:54:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-13 18:54:03       20 阅读

热门阅读

  1. P1468 [USACO2.2] 派对灯 Party Lamps

    2024-01-13 18:54:03       35 阅读
  2. Django全文搜索

    2024-01-13 18:54:03       41 阅读
  3. uni-app中实现弹幕的滚动效果

    2024-01-13 18:54:03       41 阅读
  4. 复试 || 就业day13(2024.01.09)算法篇

    2024-01-13 18:54:03       34 阅读
  5. Github Copilot: 一个强大的代码助手

    2024-01-13 18:54:03       47 阅读
  6. Android 判断网络wifi是否可用工具类

    2024-01-13 18:54:03       32 阅读
  7. AI绘画资源分享

    2024-01-13 18:54:03       25 阅读