hdu.1043.Eight (打表 || 双广 + 奇偶逆序)

Eight

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14380    Accepted Submission(s): 4044 Special Judge

Problem Description

The 15-puzzle has been around for over 100 years; even if you don‘t know it by that name, you‘ve seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let‘s call the missing tile ‘x‘; the object of the puzzle is to arrange the tiles so that they are ordered as:

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15  x

where the only legal operation is to exchange ‘x‘ with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:

 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4  5  6  7  8     5  6  7  8     5  6  7  8     5  6  7  8  9  x 10 12     9 10  x 12     9 10 11 12     9 10 11 12 13 14 11 15    13 14 11 15    13 14  x 15    13 14 15  x             r->            d->            r->

The letters in the previous row indicate which neighbor of the ‘x‘ tile is swapped with the ‘x‘ tile at each step; legal values are ‘r‘,‘l‘,‘u‘ and ‘d‘, for right, left, up, and down, respectively. 
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and  frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing ‘x‘ tile, of course). 
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three  arrangement.

Input

You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x‘. For example, this puzzle 
1 2 3  x 4 6  7 5 8 
is described by this list: 
1 2 3 x 4 6 7 5 8

Output

You will print to standard output either the word ``unsolvable‘‘, if the puzzle has no solution, or a string consisting entirely of the letters ‘r‘, ‘l‘, ‘u‘ and ‘d‘ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.

Sample Input

2 3 4 1 5 x 7 6 8

Sample Output

ullddrurdllurdruldr

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<ctype.h>
  5 typedef long long ll ;
  6 int map[5][5] ;
  7 char mp[20] ;
  8 int l , r , l1 , r1 ;
  9 int flag ;
 10 int anti ;
 11 int move[][2] = {{1,0} , {-1,0} , {0,1} , {0,-1}} ;
 12 const int mod = 400000 ;
 13 struct node
 14 {
 15     int x , y , nxt ;
 16     int map[3][3] ;
 17 } b[mod];
 18 struct hash
 19 {
 20     ll w , id ;
 21     int nxt ;
 22 }e[mod * 2];
 23 int H[mod * 2] , E ;
 24
 25 void insert (ll x , int id)
 26 {
 27     int y  = x % mod ;
 28     if (y < 0) y += mod ;
 29     e[++ E].w = x ;
 30     e[E].id = id ;
 31     e[E].nxt = H[y] ;
 32     H[y] = E ;
 33 }
 34
 35 int find (ll x)
 36 {
 37     int y = x % mod ;
 38     if (y < 0 ) y += mod ;
 39     for (int i = H[y] ; ~ i ; i = e[i].nxt ) {
 40         if (e[i].w == x)
 41             return e[i].id ;
 42     }
 43     return -1 ;
 44 }
 45
 46 void table ()
 47 {
 48     node ans , tmp ;
 49     E = -1 ;  memset (H , -1 , sizeof (H) ) ;
 50     l1 = 0 , r1= 1 ;
 51     b[l1].x = 2 , b[l1].y = 2 , b[l1].nxt = -1 ;
 52     ll sum = 0 ;
 53     for (int i = 0 ; i < 3 ; i ++) for (int j = 0 ; j < 3 ; j ++) b[l1].map[i][j] = i * 3 + j + 1 ;
 54     insert (123456789 , 0 ) ;
 55     while (l1 != r1) {
 56         ans = b[l1] ;
 57         for (int i = 0 ; i < 4 ; i ++) {
 58             tmp.x = ans.x + move[i][0] ; tmp.y = ans.y + move[i][1] ;
 59             if (tmp.x < 0 || tmp.y < 0 || tmp.x >= 3 || tmp.y >= 3) continue ;
 60             for (int i = 0 ; i < 3 ; i ++) for (int j = 0 ; j < 3 ; j ++) tmp.map[i][j] = ans.map[i][j] ;
 61             std::swap (tmp.map[ans.x][ans.y] , tmp.map[tmp.x][tmp.y]) ;
 62             sum = 0 ;
 63             for (int i = 0 ; i < 3 ; i ++) for (int j = 0 ; j < 3 ; j ++) sum = sum * 10 + tmp.map[i][j] ;
 64             if (find (sum) != -1 ) continue ;
 65             insert (sum  , r1 ) ;
 66             tmp.nxt = l1 ;
 67             b[r1 ++] = tmp ;
 68         }
 69         l1 ++ ;
 70     }
 71 }
 72
 73 void solve (int u)
 74 {
 75     if (u == -1) return ;
 76     int t = b[u].nxt ;
 77     if (t != -1) {
 78         int x = b[t].x - b[u].x , y = b[t].y - b[u].y ;
 79         if (x == 1) printf ("d") ;
 80         else if (x == -1) printf ("u") ;
 81         else if (y == 1) printf ("r") ;
 82         else if (y == - 1) printf ("l") ;
 83     }
 84     solve (t) ;
 85 }
 86
 87 int main ()
 88 {
 89     freopen ("a.txt" , "r" , stdin ) ;
 90     table () ;
 91     while (gets (mp) != NULL) {
 92         int tot = 0 ;
 93         for (int i = 0 ; mp[i] != ‘\0‘ ; i ++) {
 94             if (mp[i] != ‘ ‘) {
 95                 if (isdigit (mp[i])) {
 96                     map[tot / 3][tot % 3] = mp[i] - ‘0‘ ;
 97                 }
 98                 else map[tot / 3][tot % 3] = 9 ;
 99                 tot ++ ;
100             }
101         }
102         ll sum = 0 ;
103         for (int i = 0 ; i < 3 ; i ++) for (int j = 0 ; j < 3 ; j ++) sum = sum * 10 + map[i][j] ;
104         anti = find (sum) ;
105         if (anti != -1) solve (anti) ;
106         else printf ("unsolvable") ;
107         puts ("") ;
108     }
109     return 0 ;
110 }

打表思路很简单,也是为了对抗unsolve这种情况,从123456789最终状态产生所有状态,即可.

奇偶逆序:

逆序数:也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

结论:(是除去移动元素,(这里是9))

对源状态A与目标状态B进行规范化,使得两矩阵的元素0的位置相同;记为新的源状态A‘与目标状态B‘;
若A‘与B‘的逆序对的奇偶性相同(即A‘与B1的逆序对的奇偶性相同),则A‘必定可能转化为B‘,即A可以转化到B; 
若A‘与B‘的逆序对的奇偶性不同(即A‘与B2的逆序对的奇偶性相同),则A‘必定不可能转化为B‘,即A不可以转化到B;

也就是为了对抗unsolve.

然后用双广就OK了.

时间: 2024-10-08 11:48:16

hdu.1043.Eight (打表 || 双广 + 奇偶逆序)的相关文章

算法习题---线性表之单链表逆序打印

一:题目 逆序打印单链表中的数据,假设指针指向单链表的开始结点 二:思路 1.可以使用递归方法,来进行数据打印 2.可以借助数组空间,获取长度,逆序打印数组 3.若是可以,对链表数据使用头插法,逆序排列,然后正序打印即可 三:算法实现(这里使用方法一:递归实现简单易懂) #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #define MAXSIZE 10 #define OK 1 #def

HDU 5409 CRB and Graph 双连通缩点 + st表

HDU 5409 显然要先双连通缩成一棵树. 然后对于树上的边才有答案. 对于一条边来说, 两侧的最大值分为mx1 , mx2 , 那么 u 一定是min(mx1, mx2), v 一定是 u + 1. 这个经过仔细分析一下就能得到, 然后按dfs序建个st表就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi firs

HDU 1043 POJ 1077 八数码问题

以下内容转载自:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 八数码的八境界 研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor ove

HDU - 1043 - Eight / POJ - 1077 - Eight

先上题目: Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11243    Accepted Submission(s): 3022Special Judge Problem Description The 15-puzzle has been around for over 100 years; even if you

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

HDU 1043 Eight(八数码)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo

hdu 4715 素数打表

先利用筛法完成素数打表 再从小到大判断即可 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; const int Max = 1e6 + 50; int n; int isPrime[Max]; int tblPrime[Max];

nyoj 999——师傅又被妖怪抓走了——————【双广搜】

师傅又被妖怪抓走了 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便为师傅去化斋,等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“NO!” ,悟空一脸茫然,悟净:“师傅和二师兄都被妖怪抓走了”.悟空(晕!).为了防止悟空救人,妖怪先把唐憎和八戒分别藏起来,如果悟空在T分钟之后还没找到人,那必定是被妖怪吃

nyist 999 师傅又被妖怪抓走了 【双广搜 || BFS +状态压缩】

题目:nyist 999 师傅又被妖怪抓走了 分析:在一个图中只要看到D点和E点就行的最小步数,看到的定义是:也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方. 所以可以先预处理地图,把D点和E点所在的行列的' .'扩展为d和e,然后只要搜到d和e就可以,问题是只有d和e同时搜到才行,直接广搜肯定不行,我们可以在搜到d点之后然后在从当前点广搜e点,或者e点广搜d点,这样第一次搜到的点不一定是最优的,所以需要枚举所有情况才行,时间复杂度较高. 比较好的一种方法是BF