poj1184 聪明的打字员
IAmL
posted @ 2009年3月30日 07:12
in 解题报告
with tags
poj1184 聪明的打字员解题报告
, 5817 阅读
注:本解题报告里的有些思路不是由本人想出,是通过百度搜出来的。所以在此膜拜一下做出来的大牛们。
(个人认为)这是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;
}
2011年7月27日 20:59
我写了两个版本,一个是简单的BFS,一个是参照你的方法,但是对于下面的数据,出错了
700638 815339
简单BFS输出14,而你的输出15。
不过在poj上过了。
2020年1月28日 16:27
Download valentine day Whatsapp status free just one click rose day WhatsApp status video you can play video if you like this video then click on the download button and download video
2020年5月02日 01:11
Real difficulties can be overcome; it is only the imaginary ones that are unconquerable