uva 704
// Colour Hash (色彩缤纷游戏)
// PC/UVa IDs: 110807/704, Popularity: B, Success rate: average Level: 3
// Verdict: Accepted
// Submission Date: 2011-08-28
// UVa Run Time: 0.048s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 若从给定状态进行单向搜索,由于状态较多,容易 TLE,故采用双向搜索的办法,逆向搜索:从目标状态
// 搜索 8 步,把所有得到的结果记录在集合 A 中;正向搜索:从给定状态搜索 9 步,若在搜索过程中生成
// 的某个状态在集合 A 中,则表明在 16 步内能找到解,否则无法找到解。
//
// 这里较为关键的是如何表示游戏的当前状态,以避免在集合 A 中添加重复的状态,可以使用字符串来表示
// 当前的滑块状态。集合 A 可以使用 map 来判断是否已经有重复的状态产生。 #include <iostream>
#include <queue>
#include <map> using namespace std; #define LEFT_CLOCKWISE 1 // 左侧顺时针。
#define RIGHT_CLOCKWISE 2 // 右侧顺时针。
#define LEFT_COUNTERCLOCKWISE 3 // 左侧逆时针。
#define RIGHT_COUNTERCLOCKWISE 4 // 右侧逆时针。 #define NWHEEL 24 // 滑块总数目。
#define HALF_WHEEL 9 // 左侧滑块的数目。
#define MIDDLE_WHEEL 3 // 中间滑块的数目。
#define BACKWARD_DEPTH 8 // 逆向搜索深度。 // 目标状态。存储方式为左侧滑块-右侧滑块-中间滑块,因为编号为 10 的滑块占两个字符,故用 10 的英
// 文(ten)首字母 T 来表示。
string target = "034305650078709T90121"; // 逆向搜索的缓存,使用字符串来表示状态和旋转序列。
map < string, string > cache; // 旋转操作的逆。1 的逆为 3,2 的逆为 4,依此类推。
int reverse[] = { , , , }; // 表示滑块当前状态的结构。
struct node
{
string config; // 滑块状态。
string sequences; // 到达此位置的旋转序列。
}; // 按指定的方向旋转滑块。
void rotate(string &config, int direction)
{
// 获取中间滑块部分。
string middle = config.substr(HALF_WHEEL * ); switch (direction)
{
// 左侧滑块顺时针旋转。
case LEFT_CLOCKWISE: config[HALF_WHEEL * ] = config[HALF_WHEEL - ];
config[HALF_WHEEL * + ] = config[HALF_WHEEL - ];
config[HALF_WHEEL * + ] = middle[]; for (int i = HALF_WHEEL - ; i >= ; i--)
config[i] = config[i - ];
config[] = middle[];
config[] = middle[]; break; // 右侧滑块顺时针旋转。
case RIGHT_CLOCKWISE: config[HALF_WHEEL * ] = middle[];
config[HALF_WHEEL * + ] = config[HALF_WHEEL];
config[HALF_WHEEL * + ] = config[HALF_WHEEL + ]; for (int i = HALF_WHEEL; i <= (HALF_WHEEL * - ); i++)
config[i] = config[i + ];
config[HALF_WHEEL * - ] = middle[];
config[HALF_WHEEL * - ] = middle[]; break; // 左侧滑块逆时针旋转。
case LEFT_COUNTERCLOCKWISE: config[HALF_WHEEL * ] = middle[];
config[HALF_WHEEL * + ] = config[];
config[HALF_WHEEL * + ] = config[]; for (int i = ; i <= HALF_WHEEL - ; i++)
config[i] = config[i + ];
config[HALF_WHEEL - ] = middle[];
config[HALF_WHEEL - ] = middle[]; break; // 右侧滑块逆时针旋转。
case RIGHT_COUNTERCLOCKWISE: config[HALF_WHEEL * ] = config[HALF_WHEEL * - ];
config[HALF_WHEEL * + ] = config[HALF_WHEEL * - ];
config[HALF_WHEEL * + ] = middle[]; for (int i = * HALF_WHEEL - ; i >= HALF_WHEEL + ; i--)
config[i] = config[i - ];
config[HALF_WHEEL + ] = middle[];
config[HALF_WHEEL] = middle[]; break;
}
} // 从目标状态生成 8 步内所有可能产生的状态,使用宽度优先搜索的方法,用 map 存储生成的状态和相应
// 的旋转序列。
void backward_search(string config)
{
queue <node> open; node tmp;
tmp.config = config;
tmp.sequences = ""; open.push(tmp); while (!open.empty())
{
node copy = open.front();
open.pop(); // 当扩展的深度达到 8 层后停止在此状态上继续扩展。
if (copy.sequences.length() >= BACKWARD_DEPTH)
continue; for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++)
{
// 跳过无效的移动,例如前一步采用了左侧顺时针旋转,则当前若使用
// 左侧逆时针旋转会回到上一步的状态。
if (copy.sequences.length() > )
{
// 注意使用的是旋转操作的逆,故需还原后判断。
int last_rotate = reverse[copy.sequences[] - '' - ];
if (last_rotate != i && ((last_rotate + i) == ||
(last_rotate + i) == ))
continue;
} string t = copy.config;
rotate(t, i); if (cache.find(t) == cache.end())
{
node successor;
successor.config = t;
// 记录逆向搜索的旋转序列时,使用当前旋转的逆。
successor.sequences = (char)('' + reverse[i - ]) + copy.sequences;
open.push(successor); cache.insert(make_pair<string, string>(t, successor.sequences));
}
}
}
} // 进行正向搜索,采用宽度优先搜索模式。
bool forward_search(string config)
{
queue <node> open; node tmp;
tmp.config = config;
tmp.sequences = ""; open.push(tmp); while (!open.empty())
{
node copy = open.front();
open.pop(); // 已经找到在缓存中的状态,输出旋转序列。
if (cache.find(copy.config) != cache.end())
{
cout << copy.sequences;
map <string, string>::iterator it = cache.find(copy.config);
cout << (*it).second << endl; return true;
} // 搜索深度为 9。
if (copy.sequences.length() >= (BACKWARD_DEPTH + ))
continue; for (int i = LEFT_CLOCKWISE; i <= RIGHT_COUNTERCLOCKWISE; i++)
{
// 若前后两步构成互补状态则跳过。
if (copy.sequences.length() > )
{
int size = copy.sequences.length();
int last_rotate = copy.sequences[size - ] - '';
if (last_rotate != i && ((last_rotate + i) == ||
(last_rotate + i) == ))
continue;
} string t = copy.config;
rotate(t, i); node successor;
successor.config = t;
successor.sequences = copy.sequences + (char)('' + i); open.push(successor);
}
} return false;
} // 和目标状态比较,确定是否为已解决状态。
bool solved(string config)
{
for (int i = ; i < target.length(); i++)
if (config[i] != target[i])
return false; return true;
} int main(int ac, char *av[])
{
string config;
int c;
int cases; // 先生成逆向搜索的结果以备查。
backward_search(target); cin >> cases;
while (cases--)
{
// 读入初始状态。
config.clear();
for (int i = ; i < NWHEEL; i++)
{
cin >> c;
if (c == )
config.append(, 'T');
else
config.append(, c + '');
} // 调整表示形式。
config = config.substr(, HALF_WHEEL) +
config.substr(HALF_WHEEL + MIDDLE_WHEEL, HALF_WHEEL) +
config.substr( * HALF_WHEEL + MIDDLE_WHEEL); // 先判断是否已经为解决状态。
if (solved(config))
{
cout << "PUZZLE ALREADY SOLVED" << endl;
continue;
} // 进行正向搜索查找。
if (!forward_search(config))
cout << "NO SOLUTION WAS FOUND IN 16 STEPS" << endl;
} return ;
}
uva 704的更多相关文章
- [UVA] 704 Colour Hash
所谓"周界搜索",练习搜索的好题,双向宽搜/迭代加深均可,还有很多细节有待完善,判重有比set更优的结构,宽搜还没写,先存一下. //Writer:GhostCai &&a ...
- UVa 10012 - How Big Is It? 堆球问题 全排列+坐标模拟 数据
题意:给出几个圆的半径,贴着底下排放在一个长方形里面,求出如何摆放能使长方形底下长度最短. 由于球的个数不会超过8, 所以用全排列一个一个计算底下的长度,然后记录最短就行了. 全排列用next_per ...
- 1Z0-053 争议题目解析704
1Z0-053 争议题目解析704 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 704.View the Exhibit and examine the data manipul ...
- uva 1354 Mobile Computing ——yhx
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGcAAANuCAYAAAC7f2QuAAAgAElEQVR4nOy9XUhjWbo3vu72RRgkF5
- UVA 10564 Paths through the Hourglass[DP 打印]
UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...
- UVA 11404 Palindromic Subsequence[DP LCS 打印]
UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求L ...
- UVA&&POJ离散概率与数学期望入门练习[4]
POJ3869 Headshot 题意:给出左轮手枪的子弹序列,打了一枪没子弹,要使下一枪也没子弹概率最大应该rotate还是shoot 条件概率,|00|/(|00|+|01|)和|0|/n谁大的问 ...
- UVA计数方法练习[3]
UVA - 11538 Chess Queen 题意:n*m放置两个互相攻击的后的方案数 分开讨论行 列 两条对角线 一个求和式 可以化简后计算 // // main.cpp // uva11538 ...
- UVA数学入门训练Round1[6]
UVA - 11388 GCD LCM 题意:输入g和l,找到a和b,gcd(a,b)=g,lacm(a,b)=l,a<b且a最小 g不能整除l时无解,否则一定g,l最小 #include &l ...
随机推荐
- B5248 [2018多省省队联测]一双木棋 状压dp
这个题当时划水,得了二十分,现在来整一整. 这个题用状压来压缩边界线,然后通过记忆化搜索进行dp.我们可以观察到,其实每次转移,就是把一个1向左移一位.最后的状态设为0. 这其中还要有一个变量来记录谁 ...
- 七牛php上传下载类,集成官方文档的方法
<?phpuse Qiniu\Auth;use Qiniu\Storage\UploadManager;class qiniu{ public $_accesskey = null; publi ...
- Elasticserach 同步索引报错:ElasticSearch ClusterBlockException[blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Win10 计算机管理 打不开应急办法
最近Win10重置以后,计算机管理打不开了,经过一番尝试,通过以下命令在cmd下面可以直接打开 compmgmt 或者compmgmt.msc打开 在次特做一个记录,以备急用
- invoke与call
“调用一个委托实例” 中的 “调用” 对应的是invoke,理解为 “唤出” 更恰当.它和后面的 “在一个对象上调用方法” 中的 “调用” 稍有不同,后则对应的是call.在英语的语境中,invoke ...
- 5.7 Liquibase:与具体数据库独立的追踪、管理和应用数据库Scheme变化的工具。-mybatis-generator将数据库表反向生成对应的实体类及基于mybatis的mapper接口和xml映射文件(类似代码生成器)
一. liquibase 使用说明 功能概述:通过xml文件规范化维护数据库表结构及初始化数据. 1.配置不同环境下的数据库信息 (1)创建不同环境的数据库. (2)在resource/liquiba ...
- CSS3 3D变换实例 滚动的正方体
笔记: 2D变换 transform 位移 translateX() translateY() 简写:translate(X值,Y值) 正值向右,负值向左 旋转 rotate() rotat ...
- Django学习案例一(blog):四. 使用Admin
1. 创建超级用户 python manage.py createsuperuser 创建过程中输入用户名,并设定密码(记住). 后台管理汉化.修改settings.py中LANGUAGE_CODE ...
- 关于改变安卓Button样式,这里有一个好方法。
首先,在drawable下创建一个新的xml文件(例如我创建的为button.xml).然后在里面输入以下代码. <item> <shape> <gradient and ...
- AI.框架理论.语义网.语言间距.孤单
刷个博客,转载自于科学网:AI.框架理论.语义网.语言间距.孤单 一:引言: AI几乎是计算机科学家的梦想,自动化比计算机发展的要早的多.早期的自动化节省了大量人力,激发了人类懒惰的滋长和对自身进化缓 ...