双向广度优先搜索

本文介绍了一种使用双向BFS算法解决滑块拼图游戏的方法,通过定义节点结构和状态转换矩阵,利用哈希映射跟踪已访问状态,有效避免重复搜索,最终找到从初始状态到目标状态的最短步数。

 

https://www.luogu.org/problemnew/show/P1379

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <map>
  6 #include <algorithm>
  7 using namespace std;
  8 #define ll long long
  9 const int maxn=1e6+10;
 10 const int ci=1e6;
 11 
 12 struct node
 13 {
 14     int a[9],pos;
 15 };
 16 
 17 int f[][5]={
 18 {2,1,3},
 19 {3,0,2,4},
 20 {2,1,5},
 21 {3,0,4,6},
 22 {4,1,3,5,7},
 23 {3,2,4,8},
 24 {2,3,7},
 25 {3,4,6,8},
 26 {2,5,7},
 27 };
 28 
 29 map<int,int> ms,mt;
 30 int step,heads,tails,headt,tailt;
 31 node qs[maxn],qt[maxn];
 32 
 33 ll cal(int a[])
 34 {
 35     int i;
 36     ll j=1,sum=0;
 37     for (i=0;i<9;i++)
 38     {
 39         sum+=j*a[i];
 40         j*=9;
 41     }
 42     return sum;
 43 }
 44 
 45 void bfs_s()
 46 {
 47     int i,tail=tails,pos;
 48     ll sum;
 49     node d;
 50     step++;
 51     while (heads!=tail)
 52     {
 53         heads=(heads+1)%ci;
 54         d=qs[heads];
 55         pos=d.pos;
 56         for (i=1;i<=f[pos][0];i++)
 57         {
 58             swap(d.a[pos],d.a[f[pos][i]]);
 59             sum=cal(d.a);
 60             if (mt.find(sum)!=mt.end())
 61             {
 62                 printf("%d",step);
 63                 exit(0);
 64             }
 65             if (ms.find(sum)==ms.end())
 66             {
 67                 ms[sum]=1;
 68                 tails=(tails+1)%ci;
 69                 qs[tails]=d;
 70                 qs[tails].pos=f[pos][i];
 71             }
 72             swap(d.a[pos],d.a[f[pos][i]]);
 73         }
 74     }
 75 }
 76 
 77 void bfs_t()
 78 {
 79     int i,tail=tailt,pos;
 80     ll sum;
 81     node d;
 82     step++;
 83     while (headt!=tail)
 84     {
 85         headt=(headt+1)%ci;
 86         d=qt[headt];
 87         pos=d.pos;
 88         for (i=1;i<=f[pos][0];i++)
 89         {
 90             swap(d.a[pos],d.a[f[pos][i]]);
 91             sum=cal(d.a);
 92             if (ms.find(sum)!=ms.end())
 93             {
 94                 printf("%d",step);
 95                 exit(0);
 96             }
 97             if (mt.find(sum)==mt.end())
 98             {
 99                 mt[sum]=1;
100                 tailt=(tailt+1)%ci;
101                 qt[tailt]=d;
102                 qt[tailt].pos=f[pos][i];
103             }
104             swap(d.a[pos],d.a[f[pos][i]]);
105         }
106     }
107 }
108 
109 int main()
110 {
111     char s[10];
112     int i;
113     ll sum;
114     scanf("%s",s);
115     for (i=0;i<9;i++)
116     {
117         qs[1].a[i]=s[i]-48;
118         if (qs[1].a[i]==0)
119             qs[1].pos=i;
120     }
121     sum=cal(qs[1].a);
122     ms[sum]=1;
123 
124     strcpy(s,"123804765");
125     for (i=0;i<9;i++)
126     {
127         qt[1].a[i]=s[i]-48;
128         if (qt[1].a[i]==0)
129             qt[1].pos=i;
130     }
131     sum=cal(qt[1].a);
132     mt[sum]=1;
133     if (ms.find(sum)!=ms.end())
134     {
135         printf("0");
136         return 0;
137     }
138 
139     heads=0,tails=1,headt=0,tailt=1;
140     while (1)
141         bfs_s(),bfs_t();
142     return 0;
143 }
144 /*
145 023184765
146 
147 021345678
148 */

 

转载于:https://www.cnblogs.com/cmyg/p/10070135.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值