还是八数码问题,输入起始结束状态,输出最小字典序的操作顺序
还是用BFS打表,为了使操作最短,处理出X在不同位置不断操作能达到的各种状态,至于为什么根据X的不同处理,除了X外,其他数字可以随意替换,如:
1 2 3 3 4 5
4 5 6 => 7 8 X
7 8 X 6 2 1
可以替换成
a b c c d e
d e f => h i X
h i X f b a
经过这样的映射变换后,操作的序列不变
所以,只要将X某一位置的一种情况进行BFS得到所有状态打表,就可以将X在同一位置的起始状态映射为该状态,再用同样的映射规则处理结束状态,就可以在表中查出操作顺序
另外为了保证最小字典序,BFS中要按照 “dlru” 的顺序进行操作
/*
HDU 3567
BFS打表
*/
#include<iostream>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
constexpr int maxn = 500000;
struct node
{
//棋盘状态
vector<int> grid;
//X的位置
int pos;
};
//阶乘
vector<int> c({
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 });
//防止BFS中重复访问
bool vis[maxn];
//储存前驱状态
int pre[10][maxn];
//从前驱状态过来的操作
char step[10][maxn];
int cantor(vector<int>& permutation)
{
int res = 0;
for (int i = 0; i < 9; i++)
{
int a = 0;
for (int j = i + 1; j < 9; j++)
{
if (permutation[i] > permutation[j])
a++;
}
res += a * c[9 - i - 1];
}
return res;
}
void bfs(int k, node s)
{
memset(vis, 0, sizeof(vis));
memset(pre[k], -1, sizeof(pre[k]));
queue<node> qn;
qn.push(s);
int head = cantor(s.grid);
vis[head] = true;
while (!qn.empty())
{
node now = qn.front(); qn.pop();
int pre_val = cantor(now.grid);
if (now.pos < 6)
{
//down
swap(now.grid[now.pos], now.grid[now.pos + 3]);
int val = cantor(now.grid);
if (!vis[val])
{
vis[val] = true;
pre[k][val] = pre_val;
step[k][val] = 'd';
now.pos += 3;
qn.push(now);
now.pos -= 3;
}
swap(now.grid[now.pos], now.grid[now.pos + 3]);
}
if (now.pos != 0 && now.pos != 3 && now.pos != 6)
{
//left
swap(now.grid[now.pos], now.grid[now.pos - 1]);
int val = cantor(now.grid);
if (!vis[val])
{
vis[val] = true;
pre[k][val] = pre_val;
step[k][val] = 'l';
now.pos -= 1;
qn.push(now);
now.pos += 1;
}
swap(now.grid[now.pos], now.grid[now.pos - 1]);
}
if (now.pos != 2 && now.pos != 5 && now.pos != 8)
{
//right
swap(now.grid[now.pos], now.grid[now.pos + 1]);
int val = cantor(now.grid);
if (!vis[val])
{
vis[val] = true;
pre[k][val] = pre_val;
step[k][val] = 'r';
now.pos += 1;
qn.push(now);
now.pos -= 1;
}
swap(now.grid[now.pos], now.grid[now.pos + 1]);
}
if (now.pos > 2)
{
//up
swap(now.grid[now.pos], now.grid[now.pos - 3]);
int val = cantor(now.grid);
if (!vis[val])
{
vis[val] = true;
pre[k][val] = pre_val;
step[k][val] = 'u';
now.pos -= 3;
qn.push(now);
now.pos += 3;
}
swap(now.grid[now.pos], now.grid[now.pos - 3]);
}
}
}
void ini()
{
vector<int> tmp;
for (int i = 0; i < 9; i++)
{
int t = 1;
tmp.clear();
for (int j = 0; j < 9; j++)
{
//X在9个位置
if (i == j) tmp.push_back(9);
else
{
//其余位置依次填入1-8
tmp.push_back(t);
t++;
}
}
//搜索打表
bfs(i, {
tmp,i });
}
}
int main()
{
cin.sync_with_stdio(false);
int t;
string str;
vector<int> que;
int m[10];
ini();
cin >> t;
for (int kase = 1; kase <= t; kase++)
{
cin >> str;
int k = 0;
int j = 1;
que.clear();
for (int i = 0; i < 9; i++)
{
if (str[i] == 'X') k = i;
else
{
//映射表
m[str[i] - '0'] = j++;
}
}
cin >> str;
for (int i = 0; i < 9; i++)
{
if (str[i] == 'X') que.push_back(9);
else
{
//按照映射改变状态
que.push_back(m[str[i] - '0']);
}
}
//for (auto v : que) cout << v << " ";
//cout << endl;
int que_val = cantor(que);
string ans;
while (pre[k][que_val] != -1)
{
int tmp = pre[k][que_val];
ans.push_back(step[k][que_val]);
que_val = tmp;
}
cout << "Case " << kase << ": " << ans.length() << endl;
for (auto p = ans.rbegin(); p != ans.rend(); p++)
cout << *p;
cout << endl;
}
}
基本按照下图这个路子来搬运的一. java基础1.java 基础语法1).标识符和关键字 主要是在命名的时候注意别用到了2).Java基本数据类型、常量和变量常量 变量:变量其实就是内存中的一块小区域 变量的分类: 按位置划分:局部变量 成员变量 按数据类型划分: 基本数据类型 引用数据类型 3).运算符 (++ – 三目运算:a? b:c 等)..._抽...插...满...
方法如下:1、构建属性表2、单击道路字段下的field calculator打开如下对话框,按照箭头标示的步骤,先选择string,然后单击left()函数,这里要获取“门牌地址”的左边七个字符,即“元岗路一区五巷”,所以用如下的函数即可,最后点击OK3、得到如下效果4、根据楼主的情况,你选取的不一定都是七个字符,所以,你可以先多建立几个道路字段,如道路1,道路2,道路...
原文地址:http://developer.android.com/tools/help/translations-editor.html#running编辑翻译在该文献关于翻译编辑器运行编辑翻译管理字符串资源订购翻译服务也可以看看支持不同的语言与资源本地化提供资源如果你的应用程序支持多国语言,你需要正确地管理你的翻译字符
有一容器Container datas;删除所有值为1000的元素对于序列容器(vector、deque、string):最好的办法为erase-remove。datas.erase(std::remove(datas.begin(), datas.end(), destData), datas.end());对于list:最好的办法是直接调用成员函数remove()。datas....
连接到 MySQL 服务器由三种办法,使用 mysql 命名 、使用 Navicat MySQL 客户端和使用各种开发语言连接使用 mysql 命令连接mysql 命令一般会随着 MySQL 安装而自带,这是最基本的也是最容易连接到 MySQL 服务器的方式可以使用下面的命令连接到 MySQL 服务器mysql -u [用户名] -p [密码,可以不输入]例如使用 root 用户登录[root@l..._mysql新建连接
(特别说明:记得以下的操作使用root用户来操作,同时也参考了刘晓涛的“全程指导:Linux下JAVA环境配置”):Step0、实验环境:IP地址:192.168.1.253操作系统:RedHat Enterprise Server 4.1中文版Step1、安装所需要的软件清单:jdk-1_5_0_04-linux-i586-rpm.bin下载地址:http://ftp.isu.edu.tw/pu_red hat 系统 安装 adb
pcntl: 1.pcntl_alarm(int $seconds) 创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm()的调用都会取消之前设置的alarm信号。 参数: $seconds - 等待的秒数。如果seconds设置为0,将不会创建alarm信号。 返回值: 返回上次alarm调度(离alarm信号发送)剩余的秒数
1.先去官网下载intelJ_IDEA的最新版本,安装。下载地址:https://www.jetbrains.com/idea/download/#section=windows2.激活填入下面的license server:http://intellij.mandroid.cn/http://idea.imsxm.com/http://idea.iteblog.com
第1章主要内容和教学要求一、计算机系统计算机系统由硬件、软件组成;指令系统是硬件和软件的界面。二、计算机语言和程序设计方法计算机语言程序员与计算机沟通的语言;描述解决问题的方法和相关数据。计算机语言的级别二进制代码构成的机器语言;使用助记符的汇编语言;使用类似英语单词和语句的高级语言;C++是面向对象的高级语言...
wordpress博客建站网赚高级应用系列教程,全套课程50课,由曹鹏老师讲解! 访问密码: fbga
20160330添加:Unity3d开发VR第一讲---概述http://www.docin.com/p-1444636517.htmlUnity对某些虚拟现实设备提供了内置支持。Unity从5.3版本开始专注于虚拟现实Oculus家族设备,特别是Oculus Rift Development Kit 2(DK2)和消费版Gear VR。Unity5.3版本不再支持n
zabbix 4.0 for centos 6.5 安装部署二进制zabbix 4.0 rpm安装1.在线安装zabbix-release-4.0-1.el7.noarch.rpm编辑vim /etc/yum.repos.d/zabbix.repo文件替换源地址2.安装zabbix-server和前端3.安装mariadb,创建zabbix库,授权zabbix用户初始化mariadb二进制zab..._zabbix4.0 centos6