HDU_1401——分步双向BFS,八进制位运算压缩,map存放hash

Problem Description
Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left to right respectively.
There are four identical pieces on the board. In one move it is allowed to:
> move a piece to an empty neighboring field (up, down, left or right),
> jump over one neighboring piece to an empty field (up, down, left or right).
 
There are 4 moves allowed for each piece in the configuration shown above. As an example let's consider a piece placed in the row 4, column 4. It can be moved one row up, two rows down, one column left or two columns right.
Write a program that:
> reads two chessboard configurations from the standard input,
> verifies whether the second one is reachable from the first one in at most 8 moves,
> writes the result to the standard output.
 
Input
Each of two input lines contains 8 integers a1, a2, ..., a8 separated by single spaces and describes one configuration of pieces on the chessboard. Integers a2j-1 and a2j (1 <= j <= 4) describe the position of one piece - the row number and the column number respectively. Process to the end of file.
 
Output
The output should contain one word for each test case - YES if a configuration described in the second input line is reachable from the configuration described in the first input line in at most 8 moves, or one word NO otherwise.
 
Sample Input
4 4 4 5 5 4 6 5 2 4 3 3 3 6 4 6
 
Sample Output
YES
 
  1 #include <cstdio>
  2 #include <map>
  3 #include <queue>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 struct point
  8 {
  9     int x,y;
 10     bool check()    
 11         {
 12             if(x>=0 && x<=7 && y>=0 && y<=7)
 13                 {
 14                     return true;
 15                 }
 16             return false;
 17         }
 18 };
 19 struct chess
 20 {
 21     point pos[4];
 22     int step;
 23     bool check(int j)    
 24         {
 25             for(int i=0;i<4;i++)
 26                 {
 27                     if(i!=j && pos[j].x==pos[i].x && pos[j].y==pos[i].y)
 28                         return true;
 29                 }
 30             return false;
 31         }
 32 }start,end;
 33 
 34 const int dir[4][2]={0,1,0,-1,1,0,-1,0};
 35 map<int,int>mapint;
 36 map<int,int>::iterator it;
 37 
 38 /*
 39 对棋盘状态进行进制压缩处理,棋子坐标(x,y):0~7
 40 变成二进制:000~111,一共有4个棋子,所以一共有(x,y)坐标4个
 41 把棋型压缩成二进制形式,共24位。因为棋子都是相同的
 42 所以每次压缩前,都要对棋子坐标(x,y)进行排序,
 43 否则棋型相同棋子序号不同时,会出现不同的压缩状态 
 44 */
 45 bool cmp(point a,point b)    //按x升序排序,如果x相等就按y升序排序 
 46 {
 47     return a.x!=b.x ? a.x<b.x : a.y<b.y;    //>降序,<升序 
 48 }
 49 int get_hash(point *temp)
 50 {
 51     int res = 0;
 52     sort(temp,temp+4,cmp);
 53     for(int i=0;i<4;i++)    //枚举棋子 
 54         {
 55             res |= ( temp[i].x<<(6*i) );
 56             res |= ( temp[i].y<<(6*i+3) );
 57         }
 58     return res;
 59 }
 60 
 61 bool BFS(int flag,chess temp)    //flag=1:从起点开始搜索,flag=2:终点开始 
 62 {
 63     /*
 64     if(flag == 2)    //当从终点开始搜索时,先在存储起点搜索压缩状态的map容器中查找,是否已经到到达过终点 
 65         {
 66             it = mapint.find(get_hash(temp.pos));
 67             if(it != mapint.end())
 68                 {
 69                     return true;
 70                 }
 71         }
 72     mapint[get_hash(temp.pos)] = flag;    
 73     */    
 74     queue<chess>que;
 75     que.push(temp);
 76     
 77     while(!que.empty())
 78         {
 79             temp = que.front();
 80             que.pop();
 81             if(temp.step >= 4)    //搜索步数不超过4步 
 82                 {
 83                     continue;
 84                 }
 85             for(int i=0;i<4;i++)    //枚举方向 
 86                 {
 87                     for(int j=0;j<4;j++)    //枚举棋子 
 88                         {
 89                             chess next = temp;
 90                             next.step++;
 91                             next.pos[j].x += dir[i][0];
 92                             next.pos[j].y += dir[i][1];
 93                             
 94                             if(!next.pos[j].check())    //判断棋子是否在棋盘内 
 95                                 {
 96                                     continue;
 97                                 }
 98                             if(next.check(j))                //判断棋子j是否和其他棋子重叠 
 99                                 {
100                                     next.pos[j].x += dir[i][0];    //重叠之后再前进一步 
101                                     next.pos[j].y += dir[i][1];
102                                     if(!next.pos[j].check())        //再次检查是否越界 
103                                         {
104                                             continue;
105                                         }
106                                     if(next.check(j))                    //再次检查是否重叠 
107                                         {
108                                             continue;
109                                         }
110                                 }
111                             
112                             int hash = get_hash(next.pos);    //获得一种新的状态 
113                             it = mapint.find(hash);                //在容器中搜索这个新状态
114                              
115                             if(flag == 1)    //从起点开始的搜索 
116                                 {    

117                                     if(it == mapint.end())        //没找到,记录压缩状态,推入队列 
118                                         {
119                                             mapint[hash] = flag;
120                                             que.push(next);
121                                         }
122                                     
123                                     else if(it -> second == 2)    //找到的是终点搜索过来的状态 
124                                         {
125                                             return true;
126                                         }
127                                     
128                                 }
129                             else                //从终点开始的搜索 
130                                 {
131                                     if(it == mapint.end())        //没找到,推入队列 
132                                         {
133                                             que.push(next);        //不需要再生成压缩状态并记录了 
134                                         }
135                                     else if(it -> second == 1)    //找到的是起点搜索过来的状态 
136                                         {
137                                             return true;
138                                         }
139                                 }
140                         }
141                 }
142         }
143     return false;
144 }
145 
146 int main()
147 {
148     while(~scanf("%d%d",&start.pos[0].x,&start.pos[0].y))
149         {        
150             for(int i=1;i<4;i++)
151                 {
152                     scanf("%d%d",&start.pos[i].x,&start.pos[i].y);
153                 }
154             for(int i=0;i<4;i++)
155                 {
156                     scanf("%d%d",&end.pos[i].x,&end.pos[i].y);
157                 }
158             for(int i=0;i<4;i++)    //把棋盘坐标由1~8转化成0~7,方便进制压缩 
159                 {
160                     start.pos[i].x--;    start.pos[i].y--;
161                     end.pos[i].x--;    end.pos[i].y--;
162                 }
163             start.step = end.step = 0;
164             
165             mapint[get_hash(start.pos)] = 1;    //搜索之前先把初始压缩状态放入map容器,防止起点和终点一样的情况
166             mapint[get_hash(end.pos)] = 2;
167             
168             if(BFS(1,start) || BFS(2,end))
169                 {
170                     printf("YES\n");
171                 }
172             else
173                 {
174                     printf("NO\n");
175                 }
176             
177             mapint.clear();    //狗日的一定要记住,容器什么的每次要清空 
178         }
179     return 0;
180 }

 

posted @ 2013-07-16 22:13  瓶哥  Views(254)  Comments(0Edit  收藏  举报