题目链接:http://poj.org/problem?id=1166
思路分析:题目要求求出一个最短的操作序列来使所有的clock为0,所以使用bfs;
<1>被搜索结点的父子关系的组织:
在bfs中,队列中存储着解答树中搜索过的结点,并且每个结点都可以使用它在队列中的位置作为其唯一的ID;
另外,使用另一个数组存储结点的父节点和从父节点到该节点的操作,同样的,使用结点在队列中的位置作为该节点的ID;
这种方法类似于并查集的方法,使用多个线性数组来模拟树的结构;这里模拟解答树中搜索过的结点构成的树的结构;
<2>判重方法: 对于每个结点都有一个唯一的状态,使用位运算进行状态压缩和一个判重数组即可实现判重;
代码如下:
#include <queue> #include <vector> #include <iostream> using namespace std; const int mod = 0333333333; // 以0开头的数字代表八进制 const int MAX_N = (1 << 18) + 10; int clock[9]; bool vis[mod]; int fa[MAX_N], path[MAX_N], state_queue[MAX_N], ans[MAX_N]; char mov[9][6] = {"ABDE", "ABC", "BCEF", "ADG", "BDEFH", "CFI", "DEGH", "GHI", "EFHI"}; int Bfs(int s) { int start, head, tail; start = s; head = tail = 0; state_queue[tail++] = start; fa[0] = -1; vis[start] = true; while (head < tail) { int now = state_queue[head]; for (int i = 0; i < 9; ++i) { int k = 0, value; int next = now; while (mov[i][k] != NULL) { value = mov[i][k] - ‘A‘; next = next + (1 << (3 * value)); next = next & mod; k++; } if (!vis[next]) { fa[tail] = head; path[tail] = i + 1; if (next == 0) return tail; else { vis[next] = true; state_queue[tail++] = next; } } } head++; } return -1; } void PrintPath(int k) { int end = k, start = end; int len = 0; while (fa[start] != -1) { ans[len++] = path[start]; start = fa[start]; } for (int i = len - 1; i > 0; --i) printf("%d ", ans[i]); printf("%d\n", ans[0]); } int main() { int start, ans, temp = 0; start = 0; for (int i = 0; i < 9; ++i) { scanf("%d", &temp); start += temp << (3 * i); } ans = Bfs(start); PrintPath(ans); return 0; }
时间: 2024-10-12 13:23:07