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

题意:给出一个八数码,求出到达指定状态的路径。

思路:路径寻找问题。在这道题里用到的知识点挺多的。第一次用双向BFS来做。

①双向BFS

在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环。

②康托展开

X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! ,其中a[i]为当前未出现的元素中是排在第几个(从0开始)。这就是康托展开。

例:321的康托展开为:2*2!+1*1!+0*0!;

(数字3后比3小的数有2个,数字2后比2小的数有1个...依次类推)

③逆序数判断

每次交换两个数字逆序数的奇偶性不变,这个线代里有说过的,这样就可以根据最后状态的逆序数奇偶性来判断当前所给状态能给转换成功。不然的话好像是会超时的。

  1 #include<iostream>
  2 #include<string>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7
  8 const int maxn = 400000;
  9 const char* DIR1 = "udlr";
 10 const char* DIR2 = "durl";
 11
 12 int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320 };  //阶乘值
 13
 14 int x; //x的位置
 15
 16 int dir[] = { -3, 3, -1, 1 };
 17
 18 int vis1[maxn];
 19 int vis2[maxn];
 20
 21 char ss[] = "123456780";
 22 char str[30];
 23
 24 struct Node
 25 {
 26     int x;
 27     char str[30];
 28 };
 29
 30 struct Step
 31 {
 32     int cnt;
 33     char dir;
 34 }pre[maxn];  //记录路径
 35
 36
 37 int sequence(char a[])  //计算康托展开值
 38 {
 39     int sum = 0;
 40     for (int i = 0; i < 9; i++)
 41     {
 42         int k = 0;
 43         for (int j = i + 1; j < 9; j++)
 44         {
 45             if (a[j] < a[i])
 46                 k++;
 47         }
 48         sum += fac[9 - 1 - i] * k;
 49     }
 50     return sum;
 51 }
 52
 53
 54 void printfff(int x)  //追溯到起点输出路径
 55 {
 56     if (pre[x].cnt == -1)  return;
 57     printfff(pre[x].cnt);
 58     cout << pre[x].dir;
 59 }
 60
 61 int judge(int x, int i)   //判断是否越界
 62 {
 63     int xx = x / 3;  //行
 64     int yy = x % 3;  //列
 65     if (i == 3)
 66     {
 67         int yyy = yy + 1;
 68         if (yyy > 2)  return 0;
 69     }
 70     if (i == 2)
 71     {
 72         int yyy = yy - 1;
 73         if (yyy < 0)   return 0;
 74     }
 75     if (i == 1)
 76     {
 77         int xxx = xx + 1;
 78         if (xxx>2)    return 0;
 79     }
 80     if (i == 0)
 81     {
 82         int xxx = xx - 1;
 83         if (xxx < 0) return 0;
 84     }
 85     return 1;
 86 }
 87
 88 void bfs()
 89 {
 90     memset(vis1, 0, sizeof(vis1));
 91     memset(vis2, 0, sizeof(vis2));
 92
 93     queue<Node> q1, q2;
 94     Node p1, p2;
 95
 96     int count = 2;
 97     strcpy(p1.str, str);  //初始
 98     p1.x = x;             //初始x的位置
 99     //cout << p1.str << endl;
100     strcpy(p2.str, ss);   //终极
101     p2.x = 8;             //终极x的位置
102     //cout << p2.str << endl;
103     q1.push(p1);
104     q2.push(p2);
105     vis1[sequence(str)] = 1;
106     vis2[sequence(ss)] = 2;
107     pre[1].cnt = -1;  //起点标记
108     pre[2].cnt = -1;  //终点标记
109     while (!q1.empty() && !q2.empty())
110     {
111         Node u = q1.front();
112         q1.pop();
113         int p = sequence(u.str);
114         if (vis2[p])  //找到目标状态
115         {
116             printfff(vis1[p]);
117             int k = vis2[p];
118             while (pre[k].cnt != -1)
119             {
120                 cout << pre[k].dir;
121                 k = pre[k].cnt;
122             }
123             cout << endl;
124             return;
125         }
126         else //未找到目标状态
127         {
128             Node u2;
129             for (int i = 0; i < 4; i++)
130             {
131                 u2 = u;
132                 if (!judge(u.x, i))  continue;
133                 int xx = u.x + dir[i]; //x的新地址
134                 swap(u2.str[u.x], u2.str[xx]);
135                 u2.x = xx;
136                 int v = sequence(u2.str);
137                 if (vis1[v])  continue; //已访问
138                 vis1[v] = ++count;
139                 pre[count].dir = DIR1[i]; //记录方向
140                 pre[count].cnt = vis1[p];
141                 q1.push(u2);
142             }
143         }
144
145         u = q2.front();
146         q2.pop();
147         p = sequence(u.str);
148         if (vis1[p])
149         {
150             printfff(vis1[p]);
151             int k = vis2[p];
152             while (pre[k].cnt != -1)
153             {
154                 cout << pre[k].dir;
155                 k = pre[k].cnt;
156             }
157             cout << endl;
158             return;
159         }
160         else //未找到目标状态
161         {
162             Node u2;
163             for (int i = 0; i < 4; i++)
164             {
165                 u2 = u;
166                 if (!judge(u.x, i))  continue;
167                 int xx = u.x + dir[i]; //x的新地址
168                 swap(u2.str[u.x], u2.str[xx]);
169                 u2.x = xx;
170                 int v = sequence(u2.str);
171                 if (vis2[v])  continue; //已访问
172                 vis2[v] = ++count;
173                 pre[count].dir = DIR2[i]; //记录方向
174                 pre[count].cnt = vis2[p];
175                 q2.push(u2);
176             }
177         }
178     }
179     cout << "unsolvable" << endl;
180 }
181
182
183 int main()
184 {
185     //freopen("D:\\txt.txt", "r", stdin);
186     char s[30];
187     while (gets(s))
188     {
189         int k = 0;
190         int t = 0;
191         for (int i = 0; s[i] != NULL; i++)
192         {
193             if (s[i] == 'x')  { str[k] = '0'; x = k; }
194             else if (s[i] >= '1' && s[i] <= '8')  str[k] = s[i];
195             else continue;
196             k++;
197         }
198         str[k] = '\0';
199         //int result = sequence(ss);
200         //cout << result << endl;
201         //cout << str << endl << ss << endl << x << endl;
202
203         for (int i = 0; i<9; i++)  //逆序数判断是否可行
204         {
205             if (str[i] == '0')continue;
206             for (int j = 0; j<i; j++)
207             {
208                 if (str[j] == '0')continue;
209                 if (str[j]>str[i])t++;
210             }
211         }
212         if (t & 1) cout << "unsolvable" << endl;
213         else bfs();
214     }
215     return 0;
216 }

转载于:https://www.cnblogs.com/zyb993963526/p/6340124.html

HDU 1043 Eight(双向BFS+康托展开)相关推荐

  1. hdu.1430.魔板(bfs + 康托展开)

    魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submis ...

  2. Vijos 1029 晴天小猪历险记之Number【BFS+康托展开】

    Vijos 1029 背景 话说上一回,晴天小猪不畏千难万险.千辛万苦.千磨万难--终于爬上了那座深山,来到了那位隐者的小屋中,但它不知道,有一个问题正等待着它-- 晴天小猪一推开门,就发现那里--空 ...

  3. HDU 1430 魔板(康托展开+BFS+预处理)

    魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submis ...

  4. 历届试题+九宫重排+java_蓝桥杯 历届试题 九宫重排 (bfs+康托展开去重优化)...

    Description 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的 ...

  5. 蓝桥杯 历届试题 九宫重排 (bfs+康托展开去重优化)

    Description 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的 ...

  6. 【题解】vijos P1029 晴天小猪历险记之number(bfs 康托展开)

    显然这道题可以用bfs解决.我们可以首先得到8种横竖斜之和均为15的情况,然后给它们赋予一个值,从这八种情况扩展,开一个dis数组记录某种情况所需要的步数,然后扩展出哪种就给哪种步数+1就行了.但关键 ...

  7. HDU - 3085 Nightmare Ⅱ(双向bfs)

    题目链接:点击查看 题目大意:给出一个迷宫,一个男孩和一个女孩还有两只鬼,男孩每秒钟走3格,女孩每秒钟走1格,鬼每秒钟向四周分裂2格,问男孩和女孩能否在鬼占领迷宫之前汇合,能的话输出汇合时间,否则输出 ...

  8. HDU - 1043 Eight(bfs打表)

    题目链接:点击查看 题目大意:八数码经典问题,给出一个3*3的矩阵,其中随机分布着1~8的数字以及一个空位(我们用x来表示空位),在整个矩阵中,每一次操作都可以将x和他附近的方块互换,问经过多少次操作 ...

  9. 专题训练二 搜索进阶 HDU - 3085 Nightmare Ⅱ (双向BFS + 曼哈顿距离)

    HDU - 3085 Nightmare Ⅱ (双向BFS + 曼哈顿距离) Problem Description Last night, little erriyue had a horrible ...

最新文章

  1. 明白了缓存穿透和缓存雪崩,再了解一下缓存击穿!
  2. python进制表示方法_python 16进制表示什么
  3. 只是pip安装输错字母,你就可能中了挖矿病毒
  4. javascript二维数组转置_VBA数组拆分及维数的转换
  5. Python-OpenCV 处理图像(六):对象识别
  6. CodeForces - 1284C New Year and Permutation(组合数学+思维)
  7. 支付宝的一些小问题,注意事项等等,等用得时候在来写写
  8. BugkuCTF-MISC题贝斯手
  9. centos7没有安装ifconfig命令的解决方法
  10. xp计算机怎么共享网络,xp系统手机usb共享网络上网,xp共享上网-
  11. OC5028B 内置MOS开关降压型LED恒流驱动器
  12. 【自然语言处理】韩语基础与入门(语法篇)
  13. 有意思的开源项目分享(持续更新,勤劳的搬运工,只放一些我感兴趣的)
  14. 图片尺寸怎么修改?分享2种方法快速修改图片尺寸大小
  15. oracle spatial java 类库,Java插入Oracle Spatial空间数据
  16. Euclid算法和拓展欧几里得算法
  17. java代码实现十进制到二进制的转化
  18. 计算机PE不显示硬盘,笔记本电脑进入PE系统后认不到硬盘的解决办法
  19. 直接解决OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.OMP:
  20. Eth 2.0 会成为第一个从 PoW转PoS 的公链吗?丨SheKnows第五期

热门文章

  1. [译]通过wp-config来定制你的WordPress
  2. 瑞星:ATM出现漏洞 银行:哪有这回事?
  3. MASM6.1使用方法(适合初学者)
  4. 以get方式传递json字符串问题。
  5. hdu 2085 核反应堆
  6. RSA, ACS5.X 集成配置
  7. 做好十足准备面字节跳动,五面都过了,HR告诉我这个原因我被刷了...
  8. C++之肥大的界面之感想
  9. Android merge 标签 显示错乱
  10. kotlin的Delegates与lateinit对比