poj1184 聪明的打字员
来源:互联网 发布:ubuntu如何分区 编辑:程序博客网 时间:2024/04/30 17:14
注:本解题报告里的有些思路不是由本人想出,是通过百度搜出来的。所以在此膜拜一下做出来的大牛们。
(个人认为)这是BFS的进阶题,以前做过的BFS都是按照操作一步步来,最终找出目标状态。这题巧妙的地方在于可以无视一些操作和把操作分类。比如说:光标左移是可以无视的。因为光标移动是连续的,而且开始光标在最左边。也就是说,如果光标在第3个数的话,那么它一定经过0,1,2这几个位置。所以这时如果再考虑光标左移是没有意义的。另外就是操作分类。所谓操作分类就是把操作分为两类(这两类分别对状态做出不同的影响):一类移动光标,另一类就是直接把数加到目标状态,要注意的地方是,只有光标经过的地方才能进行加减。
这样一来,记录光标到过的位置就很重要了。一般能想到的是2^6种状态,但仔细考虑之后发现其实只有10种状态,分别是
0:0
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5
第6种状态之后会出现5这个位置,是因为swap1操作。
后记:
本题可以改进的地方有几个:
1.存储状态可以进一步压缩,据说只要10*6!就可以把所有状态存完
2.据说A*算法,但是我还没想到有效的评价函数(T_T)
3.看discuss,发现有人用双向BFS写出来了,看来我也要纠结一下如何用双向BFS写出来才行……
================传说中华丽的分割线=====================
#pragma warning(disable:4786)
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
#define N 1000000
int start, end, v[6];
bool s[N][10];
struct node
{
int state;//当前状态
int step;//移动步数
int visited;//光标到达过的位置
/*
0:0
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5
*/
};
void toArray(int n, int *v)
{
for (int i = 5; i >= 0; i--)
{
v[i] = n % 10;
n /= 10;
}
}
int toNum(int *v)
{
int ans, i;
for (i = 0, ans = 0; i < 6; i++)
ans = ans * 10 + v[i];
return ans;
}
//pos1:0 or 5, pos2:当前光标位置
int swapNum(int pos1, int pos2, int *v)
{
int tmp, ans;
//swap pos1 and pos2
tmp = v[pos1];
v[pos1] = v[pos2];
v[pos2] = tmp;
ans = toNum(v);
//把数组恢复原样
tmp = v[pos1];
v[pos1] = v[pos2];
v[pos2] = tmp;
return ans;
}
int check(node& in)
{
int tmp, res, i, a[6];
toArray(in.state, a);
tmp = in.visited;
if (tmp <= 4)
{
for (i = tmp + 1; i < 6; i++)
if (a[i] != v[i]) return -1;
for (res = 0, i = 0; i <= tmp; i++)
res += abs(a[i] - v[i]);
}
else
{
tmp -= 5;
for (i = tmp + 1; i < 5; i++)
if (a[i] != v[i]) return -1;
for (res = 0, i = 0; i <= tmp; i++)
res += abs(a[i] - v[i]);
res += abs(a[5] - v[5]);
}
return res;
}
int BFS()
{
queue<node> q;
node p;
int ori, visited, tmp, a[6], res, minimum = N;
memset(s, false, sizeof(s));
p.state = start;
p.step = 0;
p.visited = 0;
q.push(p);
s[start][0] = true;
while (!q.empty())
{
p = q.front();
q.pop();
ori = p.state;
visited = p.visited;
res = check(p);
if (res != -1)
{
if (minimum > res + p.step) minimum = p.step + res;
}
p.step++;
if (p.step >= minimum) continue;//剪枝
toArray(p.state, a);
//swap0
if (p.visited > 0)
{
if (p.visited >= 5) tmp = swapNum(0, p.visited - 5, a);
else tmp = swapNum(0, p.visited, a);
if (!s[tmp][p.visited])
{
p.state = tmp;
q.push(p);
s[tmp][p.visited] = true;
}
}
//swap1
if (p.visited < 5)
{
tmp = swapNum(5, p.visited, a);
p.visited += 5;
}
else tmp = swapNum(5, p.visited - 5, a);
if (!s[tmp][p.visited])
{
p.state = tmp;
q.push(p);
s[tmp][p.visited] = true;
}
//right
p.state = ori;
p.visited = visited;
if (p.visited < 5)
{
p.visited++;
if (!s[p.state][p.visited]) q.push(p);
}
else if (p.visited < 9)
{
p.visited++;
if (!s[p.state][p.visited]) q.push(p);
}
}
return minimum;
}
int main()
{
while (cin >> start >> end)
{
toArray(end, v);
cout << BFS() << endl;
}
return 0;
}
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
#define N 1000000
int start, end, v[6];
bool s[N][10];
struct node
{
int state;//当前状态
int step;//移动步数
int visited;//光标到达过的位置
/*
0:0
1:0, 1
2:0, 1, 2
3:0, 1, 2, 3
4:0, 1, 2, 3, 4
5:0, 5
6:0, 1, 5
7:0, 1, 2, 5
8:0, 1, 2, 3, 5
9:0, 1, 2, 3, 4, 5
*/
};
void toArray(int n, int *v)
{
for (int i = 5; i >= 0; i--)
{
v[i] = n % 10;
n /= 10;
}
}
int toNum(int *v)
{
int ans, i;
for (i = 0, ans = 0; i < 6; i++)
ans = ans * 10 + v[i];
return ans;
}
//pos1:0 or 5, pos2:当前光标位置
int swapNum(int pos1, int pos2, int *v)
{
int tmp, ans;
//swap pos1 and pos2
tmp = v[pos1];
v[pos1] = v[pos2];
v[pos2] = tmp;
ans = toNum(v);
//把数组恢复原样
tmp = v[pos1];
v[pos1] = v[pos2];
v[pos2] = tmp;
return ans;
}
int check(node& in)
{
int tmp, res, i, a[6];
toArray(in.state, a);
tmp = in.visited;
if (tmp <= 4)
{
for (i = tmp + 1; i < 6; i++)
if (a[i] != v[i]) return -1;
for (res = 0, i = 0; i <= tmp; i++)
res += abs(a[i] - v[i]);
}
else
{
tmp -= 5;
for (i = tmp + 1; i < 5; i++)
if (a[i] != v[i]) return -1;
for (res = 0, i = 0; i <= tmp; i++)
res += abs(a[i] - v[i]);
res += abs(a[5] - v[5]);
}
return res;
}
int BFS()
{
queue<node> q;
node p;
int ori, visited, tmp, a[6], res, minimum = N;
memset(s, false, sizeof(s));
p.state = start;
p.step = 0;
p.visited = 0;
q.push(p);
s[start][0] = true;
while (!q.empty())
{
p = q.front();
q.pop();
ori = p.state;
visited = p.visited;
res = check(p);
if (res != -1)
{
if (minimum > res + p.step) minimum = p.step + res;
}
p.step++;
if (p.step >= minimum) continue;//剪枝
toArray(p.state, a);
//swap0
if (p.visited > 0)
{
if (p.visited >= 5) tmp = swapNum(0, p.visited - 5, a);
else tmp = swapNum(0, p.visited, a);
if (!s[tmp][p.visited])
{
p.state = tmp;
q.push(p);
s[tmp][p.visited] = true;
}
}
//swap1
if (p.visited < 5)
{
tmp = swapNum(5, p.visited, a);
p.visited += 5;
}
else tmp = swapNum(5, p.visited - 5, a);
if (!s[tmp][p.visited])
{
p.state = tmp;
q.push(p);
s[tmp][p.visited] = true;
}
//right
p.state = ori;
p.visited = visited;
if (p.visited < 5)
{
p.visited++;
if (!s[p.state][p.visited]) q.push(p);
}
else if (p.visited < 9)
{
p.visited++;
if (!s[p.state][p.visited]) q.push(p);
}
}
return minimum;
}
int main()
{
while (cin >> start >> end)
{
toArray(end, v);
cout << BFS() << endl;
}
return 0;
}
- poj1184 聪明的打字员
- poj1184 聪明的打字员
- poj1184 聪明的打字员
- 聪明的打字员POJ1184
- poj1184 聪明的打字员 (bfs)
- poj1184聪明的打字员(操作分离+bfs)
- poj1184 聪明的打字员(BFS剪枝)
- poj1184 聪明的打字员(双向搜索)
- poj1184 聪明的打字员 BFS+剪枝
- 聪明的打字员
- POJ 聪明的打字员
- 聪明的打字员
- 【NOI2001】聪明的打字员
- poj 1184 聪明的打字员
- POJ 1184 聪明的打字员
- poj 1184 聪明的打字员
- Poj 1184 聪明的打字员 (搜索)
- 2014.7.8模拟赛【聪明的打字员】
- 面试前,先正确定位
- UNION 和UNION ALL 的区别
- 制作个人简历九大禁忌
- 由LoadCursor的第一参数赋值问题说开去
- 关于JavaScript
- poj1184 聪明的打字员
- 一条语句平均分配主表“价钱”-- 谁说我不会做了?靠,看不起他
- 关于inline函数
- mysql show命令详解
- Oracle中Decode()函数使用技巧
- C/C++中关键字static,const,inline,define,typedef的用法及其意义
- 外部JS得到客户端ID
- 好习惯影响着开发效率
- 一些常用的代码