【HDOJ3567】【预处理bfs+映射+康拓展开hash】

http://acm.hdu.edu.cn/showproblem.php?pid=3567

Eight II

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 130000/65536 K (Java/Others)
Total Submission(s): 4541    Accepted Submission(s): 990

Problem Description

Eight-puzzle, which is also called "Nine grids", comes from an old game.

In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an ‘X‘. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of ‘X‘ with one tile.

We use the symbol ‘r‘ to represent exchanging ‘X‘ with the tile on its right side, and ‘l‘ for the left side, ‘u‘ for the one above it, ‘d‘ for the one below it.

A state of the board can be represented by a string S using the rule showed below.

The problem is to operate an operation list of ‘r‘, ‘u‘, ‘l‘, ‘d‘ to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains:
1. It is of minimum length among all possible solutions.
2. It is the lexicographically smallest one of all solutions of minimum length.

Input

The first line is T (T <= 200), which means the number of test cases of this problem.
The input of each test case consists of two lines with state A occupying the first line and state B on the second line.
It is guaranteed that there is an available solution from state A to B.

Output

For each test case two lines are expected.
The first line is in the format of "Case x: d", in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
S is the operation list meeting the constraints and it should be showed on the second line.

Sample Input

2

12X453786

12345678X

564178X23

7568X4123

Sample Output

Case 1: 2

dd

Case 2: 8

urrulldr

题意:强化版本的八数码问题。(数据量T很大..而且要求输出最小字母序的操作方式)

题目分析:对于普通的八数码问题可以使用双向bfs解决,这个强化版本由于数据量过大,使用双向bfs可能也会TLE,而且使用双向bfs时反向bfs的过程不容易按最小字母序输出。

题解:由于起始状态与结束状态只是反映了一堆字母以及空格的相对位置关系,和字母本身的含义无关,所以可以预处理跑出空格X在不同位置下到达所有状态所用的最少操作方 式,然后按照每组数据给出的状态进行映射输出即可。这个过程仍然使用康拓展开进行hash。【注意:对string进行的操作真的很慢,所以康拓展开时使用int存状态,不用string】

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<stack>
  6 #include<string>
  7 using namespace std;
  8 string str1, str2;
  9 bool vis[370000];
 10 int dx[4] = { 1,0,0,-1 };
 11 int dy[4] = { 0,-1,1,0 };
 12 char cs[4] = { ‘d‘,‘l‘,‘r‘,‘u‘ };
 13 int pre[10][370000];
 14 int op[10][370000];
 15 int jc[12];
 16 int kt(int s) //康托展开
 17 {
 18     int code = 0;
 19     int st[9];
 20     for (int i = 8; i >= 0; i--, s /= 10)
 21         st[i] = s % 10;
 22     for (int i = 0; i<9; i++)
 23     {
 24         int cnt = 0;
 25         for (int j = i + 1; j<9; j++)
 26             if (st[j]<st[i]) cnt++;
 27         code += jc[8 - i] * cnt;
 28     }
 29     return code;
 30 }
 31 int skt = 0;
 32 int mypow(int x, int y) {
 33     int ans = 1;
 34     while (y) {
 35         if (y & 1)ans *= x;
 36         x *= x;
 37         y /= 2;
 38     }
 39     return ans;
 40 }
 41 void bfs(string str,int x) {
 42     memset(vis, 0, sizeof(vis));
 43     queue<int>pq;
 44     queue<int>pq2;
 45     queue<int>pq3;
 46     while (!pq.empty()) {
 47         pq.pop();
 48     }
 49     while (!pq3.empty()) {
 50         pq3.pop();
 51     }
 52     while (!pq2.empty()) {
 53         pq2.pop();
 54     }
 55     int tmps = 0;
 56     for (int i = 0; i < 9; i++) {
 57         tmps = tmps * 10 + str[i] - ‘0‘;
 58     }
 59     pq.push(tmps);
 60     pq2.push(x);
 61     int kt000 = kt(tmps);
 62     pq3.push(kt000);
 63     vis[kt000] = 1;
 64     while (!pq.empty()) {
 65         int str0 = pq.front(); pq.pop();
 66         //cout << str0 << endl;
 67         int s0 = pq2.front(); pq2.pop();
 68         int kt010 = pq3.front(); pq3.pop();
 69         for (int i = 0; i < 4; i++) {
 70             int x0 = s0 / 3;
 71             int y0 = s0 % 3;
 72             int tx = x0 + dx[i];
 73             int ty = y0 + dy[i];
 74             int s00 = tx * 3 + ty;
 75             if (tx >= 0 && ty >= 0 && ty < 3 && tx < 3) {
 76                 int str00=str0;
 77                 int skt1 = ((str0) / (mypow(10, (8 - s0)))) % 10;
 78                 str00 -= skt1*mypow(10,(8-s0));
 79                 int skt2= ((str0) / (mypow(10, (8 - s00)))) % 10;
 80                 str00 += skt2 * mypow(10,(8-s0));
 81                 str00 -= skt2 * mypow(10, (8 - s00));
 82                 str00 += skt1 * mypow(10, (8 - s0));
 83                 //str00[s00] = str0[s0];
 84                 int kt0 = kt(str00);
 85                 //skt++;
 86             //    cout << skt << endl;
 87             //    cout << kt0 << endl;
 88                 if (!vis[kt0]) {
 89                     vis[kt0] = 1;
 90                     op[x][kt0] = i;
 91                     pre[x][kt0] = kt010;
 92                     pq.push(str00);
 93                     pq2.push(s00);
 94                     pq3.push(kt0);
 95                 }
 96             }
 97         }
 98     }
 99
100 }
101 int main() {
102     int t;
103     jc[0] = 1;
104     for (int i = 1; i < 9; i++) {
105         jc[i] = jc[i - 1] * i;
106     }
107     int case1 = 1;
108     string str[9];
109     str[0] = "012345678";
110     bfs(str[0], 0);
111 //    cout << "%%%%%\n";
112     str[1] = "102345678";
113     bfs(str[1], 1);
114     str[2] = "120345678";
115     bfs(str[2], 2);
116     str[3] = "123045678";
117     bfs(str[3], 3);
118     str[4] = "123405678";
119     bfs(str[4], 4);
120     str[5] = "123450678";
121     bfs(str[5], 5);
122     str[6] = "123456078";
123     bfs(str[6], 6);
124     str[7] = "123456708";
125     bfs(str[7], 7);
126     str[8] = "123456780";
127     bfs(str[8], 8);
128     scanf("%d", &t);
129     while (t--) {
130         cin >> str1 >> str2;
131         int u;
132         for (int i = 0; i < 9; i++) {
133             if (str1[i] == ‘X‘) {
134                 str1[i] = ‘0‘;
135                 u = i;
136             }
137             if (str2[i] == ‘X‘) {
138                 str2[i] = ‘0‘;
139             }
140         }
141         char hash0[10];
142         for (int i = 0; i < 9; i++) {
143             hash0[str1[i] - ‘0‘] = str[u][i];
144         }
145         string tmp = "";
146         for (int i = 0; i < 9; i++) {
147             tmp += hash0[str2[i] - ‘0‘];
148         }
149         int s1=0, s2=0;
150         for (int i = 0; i < 9; i++) {
151             s1 = s1 * 10 + str[u][i] - ‘0‘;
152         }
153         for (int i = 0; i < 9; i++) {
154             s2 = s2 * 10 + tmp[i] - ‘0‘;
155         }
156         int sta = kt(s1);
157         int en = kt(s2);
158         stack<int>stk;
159         while (!stk.empty())stk.pop();
160         while (sta != en) {
161             stk.push(en);
162             en = pre[u][en];
163         }
164         printf("Case %d: %d\n", case1++, stk.size());
165         while (!stk.empty()) {
166             int sss = stk.top();
167             stk.pop();
168             if (sss != sta) {
169                 printf("%c",cs[op[u][sss]]);
170             }
171         }
172         printf("\n");
173     }
174     return 0;
175 }

原文地址:https://www.cnblogs.com/MekakuCityActor/p/9735741.html

时间: 2024-10-10 09:35:56

【HDOJ3567】【预处理bfs+映射+康拓展开hash】的相关文章

ACM/ICPC 之 BFS(离线)+康拓展开 (HDU1430-魔板)

魔板问题,一道经典的康拓展开+BFS问题,为了实现方便,我用string类来表示字符串,此前很少用string类(因为不够高效,而且相对来说我对char数组的相关函数比较熟),所以在这里也发现了很多容易被忽视的问题. 对于康拓展开不太熟系的可以先参看一篇博客:http://blog.csdn.net/zhongkeli/article/details/6966805 关于sting类,大家要注意,在赋值的时候,其赋值位置不能与首位置间存在未赋值部分. 题目需要转换思路的地方是: 我们需要将起始魔

Hdoj 1430 魔板 【BFS】+【康拓展开】+【预处理】

魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2139    Accepted Submission(s): 452 Problem Description 在魔方风靡全球之后不久,Rubik先生发明了它的简化版--魔板.魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示.任一时刻魔板的状态可用方块的颜

hdoj1043 Eight(逆向BFS+打表+康拓展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 思路: 由于自己对康拓展开用的太少,看到这个题没想到康拓展开,最开始打算直接转换为数字,但太占内存了,又想到可以将状态存进set,后来查了一下发现原来是考察康拓展开.另外就是需要打表预处理,这样快很多.BFS部分就是已知终点,从终点逆向搜索,并存每个状态的上一个状态以及操作,以便输出. 坑点:输入是多组输入,POJ那道题才是一组输入,卡在这一上午T_T. 有一组输入为12345678x,需要特

九宫重拍(bfs + 康拓展开)

问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的局面记为:12345678. 把第二个图的局面记为:123.46758 显然是按从上到下,从左到右的顺序记录数字,空格记为句点. 本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达.如果无论多少步都无法到达,则输出-1. 输入格式 输入第一行包含九宫的初态,第二行包含九宫的终态. 输出格式 输出最

ACM-康托展开+预处理BFS之魔板——hdu1430

魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1679    Accepted Submission(s): 354 Problem Description 在魔方风靡全球之后不久,Rubik先生发明了它的简化版--魔板.魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示.任一时刻魔板的状态可用方块的颜

UVA 10085(bfs+康拓展开)八数码问题

Description Problem A The Most Distant State Input: standard input Output: standard output The 8-puzzle is a square tray in which eight square tiles are placed. The remaining ninth square is uncovered. Each tile has a number on it. A tile that is adj

hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】

<题目链接> 题目大意:给出一个3×3的矩阵(包含1-8数字和一个字母x),经过一些移动格子上的数后得到连续的1-8,最后一格是x,要求最小移动步数. 解题分析:本题用BFS来寻找路径,为了降低复杂度,用BFS从最终的目标状态开始处理,将所有搜索到状态以及对应的路径打表记录,然后对于输入的矩阵,直接查表输出答案 即可,本题还有一个难点,就是如何判断记录已经搜索过的状态,如果使用map+string(矩阵看成一维)会超时,所以我们这里用康拓展开式来记录状态. #include<cstdio

九宫重排_康拓展开_bfs

历届试题 九宫重排 时间限制:1.0s   内存限制:256.0MB 问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的局面记为:12345678. 把第二个图的局面记为:123.46758 显然是按从上到下,从左到右的顺序记录数字,空格记为句点. 本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达.如果无论多少步都无法到达,则输出-1. 输入格

康拓展开与逆康拓展开

1.康托展开的解释 康托展开就是一种特殊的哈希函数 把一个整数X展开成如下形式: X=a[n]*n!+a[n-1]*(n-1)!+...+a[2]*2!+a[1]*1! 其中,a为整数,并且0<=a<i,i=1,2,..,n {1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个.123 132 213 231 312 321 . 代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来. 他们间的对应关系可由康托展开来找到.