poj 1077(8数码)
来源:互联网 发布:网络变压器维修 编辑:程序博客网 时间:2024/05/14 05:36
8数码,又称九宫格,应该是大家都玩过的一种游戏。在一个3*3的棋盘上放有8个棋子,棋子可以上下左右移动,要求通过移动棋子,使棋盘从一种状态转换为另一种状态。
首先,明显地,这是一个搜索问题,共有9!种状态,并不算多,使用普通BFS或双向BFS就能解决,其次,为了保存状态,可以使用康托展开,这样能减省许多空间。
普通BFS在状态空间搜索时,搜索了许多无用的状态,导致了时间的浪费,因此,可以使用A*或IDA*。
使用A*的话,可以根据当前状态处于正确位置的棋子数目来建立启发函数,而IDA*,也就是迭代加深的A*算法,是指先指定搜索深度,然后用DFS进行搜索,若找不到目标状态的话,则增加搜索深度,直到找到目标状态为止。因此,IDA*也是深度受限的DFS,其效率要比A*还要高。
另外,初始状态能转变为目标状态的前提是,两者逆序数的奇偶性一致。可以简要的证明一下:
1:当x在某一行里移动时,不会改变该状态逆序数的奇偶性(很明显,因为序列的排列根本没变,x可是不计入排列的);
2:当x与另外一行的数字交换位置时,相当于该数字连续移动了两次,而这样同样不会影响逆序数的奇偶性。
代码如下:
A*
#include <cstdio>#include <stack>#include <set>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>#include <string>#include <map>#include <iomanip>#include <cmath>#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define F first#define S second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define BitCount(x) __builtin_popcount(x)#define BitCountll(x) __builtin_popcountll(x)#define LeftPos(x) 32 - __builtin_clz(x) - 1#define LeftPosll(x) 64 - __builtin_clzll(x) - 1const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;using namespace std;const double eps = 1e-8;const int MAXN = 300 + 10;const int MOD = 1000007;const int M=20010;const int N=500010;const int d[][2] = { {0,1},{0,-1},{-1,0},{1,0} };typedef pair<int, int> pii;int f[9];bool vis[N];char dir[4]={ 'r','l','u','d' };struct node{ int state,step,pre; // 状态, 步骤,父亲结点 int f,h; char c;}dis[N];struct cmp{ bool operator()(node a,node b) { return a.f>b.f; }};int getX(const char g[]){ for (int i=0;i<9;i++) if (g[i]=='9') return i;}int getH(const char g[]) { int sum=0; for (int i=0;i<9;i++) { int t=g[i]-'1'; sum+=abs(t/3-i/3)+abs(t%3-i%3); // 该位置的数字与应该在这个位置的数字的横纵坐标差值之和 } return sum;}bool niu(char s[]) // 判断是否有解{ int i,j,cnt=0; for (i=0;i<9;i++) { if (s[i]=='9') continue; for (j=i+1;j<9;j++) { if (s[j]=='9') continue; if (s[i]>s[j]) cnt++; } } if (cnt&1) return false; else return true;}int KT(const char s[]) // 康托展开{ int i,j,sum=0; for (i=0;i<9;i++) { int t=0; for (j=i+1;j<9;j++) if (s[i]>s[j]) t++; sum+=t*f[8-i]; } return sum;}void invKT(char s[],int state) // 康托逆展开{ int i,j; bool a[10]; MS(a,false); //state--; for (i=0;i<9;i++) { int t=state/f[8-i] ; for (j=0;j<9;j++) if (!a[j]) { if (!t) break; t--; } s[i]=j+'1'; a[j]=true; state%=f[8-i]; } s[i]='\0';}bool astar(int state){ int i,j; char s[10]; node t; t.state=state; t.step=0; t.pre=-1; dis[state]=t; priority_queue<node,vector<node>,cmp> q; q.push(t); MS(vis,false); vis[state]=true; while(!q.empty()){ t=q.top(); q.pop(); if (!t.state) return true; invKT(s,t.state); int pos=getX(s); int x=pos/3,y=pos%3; for (i=0;i<4;i++){ int xx=x+d[i][0]; int yy=y+d[i][1]; if (xx>=0 && xx<3 && yy>=0 && yy<3) { swap(s[x*3+y],s[xx*3+yy]); int temp=KT(s); if (!vis[temp]) { node t2; t2.state=temp; // 结点自身的状态 t2.step=t.step+1; t2.h=getH(s); t2.f=t2.h+t2.step; t2.pre=t.state; // 父亲结点的状态 t2.c=dir[i]; // 方向 dis[temp]=t2; q.push(t2); vis[temp]=true; } swap(s[x*3+y],s[xx*3+yy]); } } } return false;}void print(int state){ if (dis[state].pre==-1) return; print(dis[state].pre); printf("%c",dis[state].c);}int main(){ int i,j; char ch,s[10]; f[0]=f[1]=1; for (i=2;i<=9;i++) f[i]=f[i-1]*i; while(cin>>ch) { if (ch=='x') s[0]='9'; else s[0]=ch; for (i=1;i<9;){ scanf("%c",&ch); if (isdigit(ch)) s[i++]=ch; else if (ch=='x') { s[i++]='9'; } } s[i]='\0'; int t=KT(s); if (niu(s) && astar(t)) { print(0); cout<<endl; } else puts("unsolvable"); }}
IDA*
#include <cstdio>#include <stack>#include <set>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>#include <string>#include <map>#include <iomanip>#include <cmath>#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define F first#define S second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define BitCount(x) __builtin_popcount(x)#define BitCountll(x) __builtin_popcountll(x)#define LeftPos(x) 32 - __builtin_clz(x) - 1#define LeftPosll(x) 64 - __builtin_clzll(x) - 1const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;using namespace std;const double eps = 1e-8;const int MAXN = 300 + 10;const int MOD = 1000007;const int M=20010;const int N=500010;const int d[][2] = { {0,1},{0,-1},{-1,0},{1,0} };typedef pair<int, int> pii;int f[9],path[N];bool vis[N];int pathLen,limit;int next[9][4]= // 行表示x在九宫格的位置,4列表示4个方向,表示移动后的位置,-1表示越界{ {-1,3,1,-1}, {0,4,2,-1}, {1,5,-1,-1}, {-1,6,4,0}, {3,7,5,1}, {4,8,-1,2}, {-1,-1,7,3}, {6,-1,8,4}, {7,-1,-1,5}};inline int getX(const char g[]){ for (int i=0;i<9;i++) if (g[i]=='9') return i;}int getH(const char g[]){ int sum=0; for (int i=0;i<9;i++) { int t=g[i]-'1'; sum+=abs(t/3-i/3)+abs(t%3-i%3); // 该位置的数字与应该在这个位置的数字的横纵坐标差值 } return sum;}int KT(const char s[]){ int i,j,sum=0; for (i=0;i<9;i++) { int t=0; for (j=i+1;j<9;j++) if (s[i]>s[j]) t++; sum+=t*f[8-i]; } return sum;}int niu(const char s[]){ int i,j,cnt=0; for (i=0;i<9;i++) { if (s[i]=='9') continue; for (j=i+1;j<9;j++) { if (s[j]=='9') continue; if (s[i]>s[j]) cnt++; } } return cnt;}bool ID_Astar(char s[],int len,int x){ int i,j; int state=KT(s); if (len<=limit){ if (state==0) { pathLen=len; return true; } }else return false; // over the limit for (i=0;i<4;i++){ if (next[x][i]==-1) continue; // 不能向该方向移动 if (len>0 && abs(i-path[len-1])==2) continue; // 不向上一次的相反方向移动 swap(s[x],s[next[x][i]]); int t=getH(s); path[len]=i; if (t+len<=limit && ID_Astar(s,len+1,next[x][i])) return true; swap(s[x],s[next[x][i]]); } return false;}void print(){ for (int i=0;i<pathLen;i++){ switch(path[i]) { case 0: printf("l"); break; case 1: printf("d"); break; case 2: printf("r"); break; case 3: printf("u"); break; } }}int main(){ int i,j; char ch,s[10]; f[0]=f[1]=1; for (i=2;i<=9;i++) f[i]=f[i-1]*i; while(cin>>ch) { if (ch=='x') s[0]='9'; else s[0]=ch; for (i=1;i<9;){ scanf("%c",&ch); if (isdigit(ch)) s[i++]=ch; else if (ch=='x') { s[i++]='9'; } } s[i]='\0'; int t=getX(s); limit=getH(s); if ((niu(s)&1)==0) { while (!ID_Astar(s,0,t)) limit++; print(); cout<<endl; //puts("Y"); } else puts("unsolvable"); }}
0 0
- poj 1077(8数码)
- poj 1077 八数码
- poj 1077 八数码
- poj 1077 八数码
- poj 1077 八数码难题
- poj 1077 八数码 ida*
- POJ 1077 八数码问题
- poj-1077 八数码 【a*】
- POJ 1077 八数码问题
- poj 1077 bfs+康托展开(8数码问题)
- POJ 1077 Eight(BFS八数码问题)
- POJ 1077 Eight, 八数码问题
- Poj 1077 Eight 八数码问题 (搜索)
- POJ 1077 八数码问题 练习搜索
- POJ 1077 八数码-第一道IDA*
- 八数码A*【POJ-1077 HDU-1043】
- POJ 1077 Eight 八数码问题 BFS
- POJ 1077 Eight 八数码问题 A*
- python,ipython,wxPython安装
- Exadata的OS用戶密码过期
- 数据库设计原则
- Maven最佳实践:划分模块
- Xcode的调试技巧
- poj 1077(8数码)
- Divide Two Integers
- 如何提高MYSQL数据库的查询统计速度 select 索引应用
- 英文面试
- 多进程和多线程的选择
- 设计模式之代理模式
- 从博客专栏想到的数据分析
- C++继承经典例子
- 【探索】 - 设计模式之单例模式