hdu 1043(经典搜索)
来源:互联网 发布:数据库系统及其应用 编辑:程序博客网 时间:2024/05/22 13:05
题意:
给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径
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 1213 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x r-> d-> r->
好像有很多中方法解决这个问题:八数码的八个境界
①bfs + 康托展开+打表 /* 其他的还不会,有空去试试 - -
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <cstdlib>#include <queue>#include <algorithm>typedef long long ll;using namespace std;const int MAXN=362900;//最多是9!/2int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重// 0!1!2!3! 4! 5! 6! 7! 8! 9!bool vis[MAXN];//标记char path[MAXN][40];//记录路径int cantor(int s[])//康拖展开求该序列的hash值{ int sum=0; for(int i=0; i<9; i++) { int num=0; for(int j=i+1; j<9; j++) if(s[j]<s[i])num++; sum+=(num*fac[9-i-1]); } return sum+1;}struct node{ int matri[10]; int position; char path[50]; int state;};queue<node>que;char dire[5] = "dlur";int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};void bfs(){ memset(vis,false,sizeof(vis)); node cur; for(int i = 0; i < 8; i++) cur.matri[i] = i+1; cur.matri[8] = 0; cur.state = 46234; cur.path[0] = '\0'; cur.position = 8; que.push(cur); vis[cur.state] = true; path[cur.state][0] = '\0'; while(!que.empty()) { cur = que.front(); que.pop(); int x = cur.position/3; int y = cur.position%3; for(int i = 0; i < 4; i++) { int tx = x + dir[i][0]; int ty = y + dir[i][1]; if(tx < 0 || tx > 2 || ty < 0 || ty > 2) continue; node t = cur; t.position =tx*3+ty; t.matri[cur.position] = t.matri[t.position]; t.matri[t.position] = 0; t.state =cantor(t.matri); if(!vis[t.state]) { path[t.state][0] = t.path[0] = dire[i]; int len = strlen(cur.path); for(int j = 1;j <= len+1;j++) path[t.state][j] = t.path[j] = cur.path[j-1]; vis[t.state] = true; que.push(t); } } }}char ch;int q[10];int main(){ bfs(); while(cin >> ch) { if(ch == 'x') q[0] = 0; else q[0] = ch-'0'; for(int i = 1; i < 9; i++) { cin >> ch; if(ch == 'x') q[i] = 0; else q[i] = ch-'0'; } int ans = cantor(q); // printf("%d\n",ans); if(!vis[ans]) printf("unsolvable\n"); else { cout <<path[ans]<<endl; } } return 0;}
②双向bfs + 康拓展开+奇偶剪枝
剪枝:当x左右移动时,序列不变;上下移动时,移动2位后逆序数+2,所以奇偶性不变
双向bfs:因为扩展越大,你要搜索的部分就更多.而同时从开头和结果开始理论上来说会快很多
#include <iostream>#include <cstdio>#include <cstring>#include <ctime>#include <algorithm>#include <cmath>#include <queue>#include <map>#include <vector>typedef long long ll;using namespace std;const int MAXN=370000;int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重// 0!1!2!3! 4! 5! 6! 7! 8! 9!int vis[MAXN];//标记int vis2[MAXN];int cantor(string s)//康拖展开求该序列的hash值{ int sum=0; for(int i=0; i<9; i++) { int num=0; for(int j=i+1; j<9; j++) if(s[j]<s[i])num++; sum+=(num*fac[9-i-1]); } return sum+1;}struct node{ string path; int state;} From;struct node2{ int num; char ch;} pre[MAXN];char dire2[5] = "dlur";char dire1[5] = "urdl";int dir[4] = {-3,1,3,-1};void pri(int t){ if(pre[t].num == -1) return ; pri(pre[t].num); printf("%c",pre[t].ch);}void bfs(node cur){ queue<node>que1; queue<node>que2; memset(vis,0,sizeof(vis)); memset(vis2,0,sizeof(vis2)); pre[0].num = pre[1].num = pre[2].num = -1; node last,tp; vis[cantor(cur.path)] = 1; last.path ="123456780"; last.state = 8; vis2[cantor(last.path)] = 2; que1.push(From); que2.push(last); int num = 2; while(!que1.empty() && !que2.empty()) { //正向搜索 cur = que1.front(); que1.pop(); int stat = cantor(cur.path); if(vis2[stat]) { pri(vis[stat]); int k = vis2[stat]; while(pre[k].num != -1) { printf("%c",pre[k].ch); k = pre[k].num; } printf("\n"); return; } for(int i = 0; i < 4; i++) { if(i==0&&cur.state<3)continue; //up if(i==1&&cur.state%3 == 2)continue; //right if(i==2&&cur.state>5)continue; //down if(i==3&&cur.state%3 == 0)continue; //left int posi = cur.state + dir[i]; tp = cur; swap(tp.path[cur.state],tp.path[posi]); int x = cantor(tp.path); if(vis[x]) continue; vis[x] = ++num; tp.state = posi; pre[num].ch = dire1[i]; pre[num].num = vis[stat]; que1.push(tp); } //反向搜索 last = que2.front(); que2.pop(); stat = cantor(last.path); if(vis[stat]) { pri(vis[stat]); int k =vis2[stat]; while(pre[k].num!=-1) { printf("%c",pre[k].ch); k=pre[k].num; } printf("\n"); return ; } for(int i = 0; i < 4; i++) { if(i==0&&last.state<3)continue; if(i==1&&last.state%3==2)continue; if(i==2&&last.state>5)continue; if(i==3&&last.state%3==0)continue; int posi = last.state + dir[i]; tp = last; swap(tp.path[last.state],tp.path[posi]); int x = cantor(tp.path); if(vis2[x]) continue; vis2[x] = ++num; tp.state = posi; pre[num].ch = dire2[i]; pre[num].num = vis2[stat]; que2.push(tp); } } printf("unsolvable\n");}bool check(string a){ int num = 0; for(int i = 0; i < 9; i++) { if(a[i] == '0' ) continue; for(int j = i+1; j < 9; j++) { if(a[j] == '0') continue; if(a[j] < a[i]) num++; } } if(num & 1) return true; else return false;}char ch;char a[100];int p[10];int main(){ while(gets(a)) { int tnum = 0; int n=strlen(a); From.path=""; for(int i=0; i<n; i++) if(a[i]!=' ') { if(a[i]=='x') { From.state=tnum; From.path+='0'; } else From.path+=a[i]; tnum++; } if(check(From.path))printf("unsolvable\n"); else bfs(From); } return 0;}
③A*算法+康拓展开+奇偶剪枝
它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。走到终点的代价为f[n],主要由已经花费的代价g[n]和将要花费的代价h[n]决定,f[n] = g[n] + h[n],由于要找最短的路径,优先判定f[n]较小的。
而在本题中g[n]即是已经走过的步数,h[n]则是当前情况移动到-> 123456780的最小步数.
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <cstdlib>#include <queue>#include <algorithm>typedef long long ll;using namespace std;const int MAXN=362880;int fac[]= {1,1,2,6,24,120,720,5040,40320,362880};// 0!1!2!3! 4! 5! 6! 7! 8! 9!int vis[MAXN];int cantor(int s[]){ int sum=0; for(int i=0; i<9; i++) { int num=0; for(int j=0; j<i; j++) if(s[j]>s[i])num++; sum+=(num*fac[i]); } return sum;}struct node2{ int pre; char ch;} pre[MAXN];struct node{ int matri[10]; int position; int have,to; int state; bool operator < (const node a)const { return have+to>a.have+a.to; }};char dire[5] = "urdl";int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};int fx[]={2,0,0,0,1,1,1,2,2},fy[]={2,0,1,2,0,1,2,0,1};int get_(node a){ int ans = 0; for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++){ if(a.matri[i*3+j]){ ans+=abs(i-fx[a.matri[i*3+j]])+abs(j-fy[a.matri[i*3+j]]); } } return ans;}int fina[10];void pri(int k){ if(pre[k].pre == -1) return; pri(pre[k].pre); printf("%c",pre[k].ch);}void bfs(node cur){ priority_queue<node>que; memset(vis,0,sizeof(vis)); vis[cur.state] = 1; int tnum = 1; pre[1].pre = -1; for(int i = 0; i < 8; i++) fina[i] = i+1; fina[8] = 0; int _ans = cantor(fina); cur.have = 0; que.push(cur); while(!que.empty()) { cur = que.top(); que.pop(); int x = cur.position/3; int y = cur.position%3; int num = cur.state; if(num == _ans) { int k = vis[num]; pri(k); printf("\n"); return ; } for(int i = 0; i < 4; i++) { int tx = x + dir[i][0]; int ty = y + dir[i][1]; if(tx < 0 || tx > 2 || ty < 0 || ty > 2) continue; node t = cur; t.position =tx*3+ty; t.matri[cur.position] = t.matri[t.position]; t.matri[t.position] = 0; t.have++; t.to = get_(t); t.state =cantor(t.matri); if(!vis[t.state]) { vis[t.state] = ++tnum; pre[tnum].pre = vis[num]; pre[tnum].ch = dire[i]; que.push(t); } } } printf("unsolvable\n");}bool check(int a[]){ int num = 0; for(int i = 0; i < 9; i++) { if(a[i] == 0 ) continue; for(int j = i+1; j < 9; j++) { if(a[j] == 0) continue; if(a[j] < a[i]) num++; } } if(num & 1) return true; else return false;}char ch;int main(){ while(cin >> ch) { node from; if(ch == 'x') { from.matri[0] = 0; from.position = 0; } else from.matri[0] = ch-'0'; for(int i = 1; i < 9; i++) { cin >> ch; if(ch == 'x') { from.matri[i] = 0; from.position = i; } else from.matri[i] = ch-'0'; } int ans = cantor(from.matri); from.state = ans; // printf("%d\n",ans); if(check(from.matri)) printf("unsolvable\n"); else bfs(from); } return 0;}
0 0
- hdu 1043(经典搜索)
- hdu 1455 搜索经典
- hdu 1455 Sticks(经典搜索)
- hdu 1043/poj 1077 Eight (八数码 经典搜索题 bfs + 康托展开)
- hdu 1043 八数码 经典搜索问题 BFS+MAP
- HDU 1010 Tempter of the Bone(搜索经典题)
- HDU 5335 Walk Out (搜索+贪心,超详解)经典
- HDU-1238-Substrings搜索经典题目
- hdu 1518 又一道搜索经典
- HDU 2102 A计划 经典搜索~
- HDU 1043 八数码(A*搜索)
- HDU 1078(搜索)
- hdu 2553 N皇后问题 经典搜索,DFS解法
- hdu 1560 DNA sequence(迭代加深搜索)(经典题)
- hdu 1016 经典的dfs搜索 acm 杭电 OJ
- hdu 1078 FatMouse and Cheese【经典记忆化搜索】
- HDU-1043 Eight(经典八数码问题, A*+康拓+曼哈顿距离+逆序数判断可解性、双向搜索)
- 【搜索进阶】hdu 1043 Eight
- ocp-306
- Delphi XE8 TMultiView的使用
- MCS-51单片机的存储器组织结构
- coredata swift 简单入门
- Trie树(单词查找树)
- hdu 1043(经典搜索)
- 【LeetCode 234】Palindrome Linked List 解题报告.
- 纯CSS改写checkbox样式,让复选框看起来更舒服一些
- MySQL建库建表和修改表结构
- ocp-307
- javac.exe、 java.exe、 java虚拟机三者之间的区别与联系
- 黑马程序员—String,StringBuffer,StringBuilder的常用方法与特点
- 避免僵死进程
- iOS图片内存优化