poj1198

poj1198:

 

Solitaire

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. 

广度优先搜索求最小路径(其实原题给定了最大步数,深搜搜到第八步跳出循环也可以解决,但是容易超时)。

根据广度优先搜索的几个基本步骤,在写题之前先把思路整理好:

  1. 每个结点的棋盘都将只有四个点是棋子,也就是说,与其用8x8 的数组存储,不如只存坐标
  2. 每个父结点的每个棋子都有4种走法,四个棋子有16种走法。如果搜到8步,那将是168,也就是232=429496729,数组开不下,并且必定会超时。

解决的办法有两个:

  1. 判重并且使用到哈希解码,对于冲突,我们可以用字符串记录路径,发生冲突时叠加字符串即可。对于判重,从头到尾的比较肯定会超时,我们可以开一个86878889长度的数组(可能出现的最大项,可以用平移优化),用来打标记判重
  2. 我们可以写一个双向BFS(个人更喜欢这种做法),双向搜索只需要搜4层就够了。

值得注意的是,如果开数组打标记的方法判重,一定要把每个结点的四个坐标都排好序

以下是代码

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 //定义棋子 
  7 struct point{
  8     int x, y;
  9 };
 10 //定义初始、目标棋盘 
 11 point a[5], b[5];
 12 int numa, numb;
 13 //输出棋盘 
 14 void print(point a[5]){
 15     
 16     for (int i=1; i<=4; ++i) printf("%d%d", a[i].x, a[i].y);
 17     printf("\n");
 18     
 19 }
 20 
 21 //将棋盘转换为十进制数 
 22 int f(point a[5]){
 23     int s=0;
 24     for (int i=1; i<=4; ++i) s=s*100+a[i].x*10+a[i].y;
 25     return s;
 26  27 bool cmp(point a, point b){
 28     return a.x<b.x or (a.x==b.x and a.y<b.y);
 29 }
 30 
 31 //偏移量
 32 point d[5]={00},
 33             {+10},
 34             {-10},
 35             { 0,+1},
 36             { 0,-1}};
 37         
 38 //定义判重的数组 flag
 39 bool flag[85868789];
 40 //定义节点
 41 struct node{
 42     point a[5];
 43     int dep;
 44     int fa;
 45 }; 
 46 node data[6000000]; 
 47 //判断x,y位置是否出界 
 48 bool check(int x, int y){
 49     return (x>=1 and x<=8 and y>=1 and y<=8);
 50 }
 51 //检查a棋盘的x,y位置是否有棋子 有返回真 
 52 bool check1(point a[5], int x, int y){
 53     for (int i=1; i<=4; ++i)
 54         if (a[i].x==x and a[i].y==y) return true;
 55     return false;
 56 }
 57 //复制棋盘 
 58 void copy1(point a[5], point b[5]){
 59     for (int i=1; i<=4; ++i) b[i].x=a[i].x,b[i].y=a[i].y;
 60 }
 61 int op , cl;
 62 void print1(int cl){
 63     
 64     int ans[10], n=0;
 65     while (cl!=-1){
 66         ans[++n]=cl;
 67         cl=data[cl].fa;
 68     }
 69     printf("\n\n");
 70     for (int i=n; i>1; --i) print(data[ans[i]].a);
 71     print(data[ans[1]].a);
 72 }
 73 int main(){
 74     //freopen("poj1198.in", "r", stdin);
 75     for (int i=1; i<=4; ++i) scanf("%d%d", &a[i].x, &a[i].y);   
 76     for (int i=1; i<=4; ++i) scanf("%d%d", &b[i].x, &b[i].y);
 77     //print(a);
 78     //print(b);
 79     sort(a+1, a+5, cmp);
 80     sort(b+1, b+5, cmp);
 81     numa=f(a);
 82     numb=f(b);
 83     //print(a);
 84     //print(b);
 85     //printf("%d %d\n", numa, numb); 
 86     //特判初始状态和目标状态
 87     if (numa==numb){
 88         
 89         printf("YES");
 90         return 0;
 91         
 92     } 
 93     //初始化 首节点入队 首尾设置指针 
 94     copy1(a, data[1].a); data[1].dep=0; data[1].fa=-1;
 95     //memset(flag, false, sizeof flag);
 96     flag[numa]=true;
 97     
 98     op = 0, cl = 1;
 99     bool f1=false;
100     while (op<cl and !f1 and data[op+1].dep<8){
101         ++op;
102         
103         int dep=data[op].dep;
104         
105         for (int i=1; i<=4; ++i){
106             
107             for (int j=1; j<=4; ++j){
108                 
109                 copy1(data[op].a, a);  //每个操作要从原始棋盘开始
110                 
111                 //x1,y1移动一步的位置
112                 //x2,y2跳跃一步的位置 
113                 int x1=a[i].x+d[j].x, y1=a[i].y+d[j].y;
114                 int x2=x1+d[j].x, y2=y1+d[j].y;
115                 
116                 if (check(x1, y1) and !check1(a, x1, y1)) {//x1,y1位置不出界且x1,y1位置无棋子 
117                     
118                     a[i].x=x1; a[i].y=y1;   //移动到新位置
119                     sort(a+1, a+5, cmp);    //排序
120                     numa=f(a);              //转化为数
121                     if (!flag[numa]){       //判重
122                         flag[numa]=true;    //标记 
123                         
124                         ++cl;               //入队 
125                         copy1(a, data[cl].a);
126                         data[cl].dep=dep+1;
127                         data[cl].fa=op;
128                         
129                         //判断目标
130                         if (numa==numb){
131                             f1=true;
132                             break;
133                         }
134                     }   
135                 }else
136                 if (check(x1, y1) and check(x2, y2) and 
137                     check1(a, x1, y1) and !check1(a, x2, y2)) {
138                     //x1,y1,x2,y2位置不出界且x1,y1位置有棋子,x2,y2位置无棋子
139                     
140                     a[i].x=x2; a[i].y=y2;   //跳跃到新位置 
141                     sort(a+1, a+5, cmp);    //排序 
142                     numa=f(a);              //转化为数 
143                     if (!flag[numa]){       //判重 
144                         flag[numa]=true;    //标记 
145                         
146                         ++cl;               //入队 
147                         copy1(a, data[cl].a);
148                         data[cl].dep=dep+1;
149                         data[cl].fa=op;
150                         
151                         //判断目标 
152                         if (numa==numb){
153                             f1=true;
154                             break;
155                         }
156                     }   
157                 }
158             }
159             if (f1) break;
160         }
161     }
162     if (f1) printf("YES\n"); else printf("NO\n");
163     return 0;
164 }

 

转载于:https://www.cnblogs.com/hnoi/p/10922637.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值