八数码难题 hdu1043/ poj1077
来源:互联网 发布:网络爬虫基本原理 编辑:程序博客网 时间:2024/04/29 12:38
一组数据 ,正向搜索。 poj 1077
代码如下: A* + hash +堆 + 曼哈顿距离 做一组数据的poj1077,可是,但是对于hdu 1043多组数据,没有剪枝,故超时,下面再给剪枝改进的算法。
1 #include<iostream> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 #include<string.h> 6 #include<string> 7 #include<queue> 8 #include<algorithm> 9 #define N 363000 // 9! = 362880 10 using namespace std; 11 12 struct node{ 13 int ma[9]; 14 int ans1; //哈希值 15 int x; // 记录x可移动的位置,记为9 16 int f; // 估价函数 17 int g; // 深度 18 string path; 19 bool operator <(const node & a)const{ 20 return f>a.f; //优先访问估价函数值f较小的节点 21 } 22 }; 23 int visited[N]; 24 string path; 25 node start; 26 int end = 0; // 123456789对应的哈希值 27 int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; // 上-右-下-左 28 char index[5]="urdl"; 29 // 哈希表,排列逆序,用于判重 30 int fact[] = {1, 1, 2, 6, 24,120 ,720, 5040, 40320}; // 康托展开数列 31 //0! 1! 2! 3! 4! 5! 6! 7! 8! 32 int hash(int *s) // 返回每个排列的哈希值 33 { 34 int sum=0; 35 for(int i=0;i< 9;i++) 36 { 37 int num=0; // 计算 第i位数的逆序数 38 for(int j=0;j<i;j++) 39 if(s[i]<s[j]) 40 num++; 41 sum+= num * fact[i]; // sum的取值范围是 0---9!-1 42 } 43 return sum; 44 } 45 int ABS(int x){return x>0?x:(-x);} //求绝对值 46 int h_juli(int *s) // 不算x时的 曼哈顿距离启发函数,计算的是 从第n个点到目标点的最小代价 47 { 48 int tx,ty,endx,endy,tmp; // 逆序搜索,从目标状态为起点 49 int sum=0; 50 for(int i=0;i<9;i++) 51 { 52 if(s[i]== 9) continue; 53 tmp=s[i]; 54 tx= i /3; 55 ty= i %3 ; 56 endx = (tmp-1)/3; 57 endy = (tmp-1)%3; 58 sum+=ABS(tx-endx) + ABS(ty- endy); 59 } 60 return sum; 61 } 62 63 //广度优先搜索 64 int bfs() 65 { 66 priority_queue<node>q; 67 node now,next; 68 int x ,y,ans; 69 now= start; 70 now.ans1=hash(now.ma); 71 now.path=""; 72 if(now.ans1 == end){ 73 path=now.path; 74 return 1; 75 } 76 visited[now.ans1] =1; // 访问起始节点 77 now.g = 0; // 深度置为0 78 now.f = h_juli(now.ma); 79 q.push(now); //将顶点now压入队列 80 while(!q.empty()) 81 { 82 now =q.top(); //取出队列头的顶点,设为now 83 q.pop(); 84 x= now.x /3; 85 y= now.x %3; 86 for(int i=0;i<4;i++) 87 { 88 int tx= x+dir[i][0]; 89 int ty= y+dir[i][1]; 90 if(ty<0 || ty>2 || tx<0 || tx>2) continue; 91 next=now; // next 为 now的邻接顶点 92 next.x= tx*3+ty; 93 next.ma[now.x] = now.ma[next.x]; 94 next.ma[next.x] = 9; 95 ans = hash(next.ma); 96 if(!visited[ans] ) //且next没有访问过,访问next顶点,对next赋值,并将next加入队列 97 { 98 visited[ans]=1; 99 next.ans1=ans;100 next.g++;101 next.f= next.g+h_juli(next.ma);102 next.path+=index[i];103 if(next.ans1 == end){104 path=next.path;105 return 1;106 }107 q.push(next);108 }109 110 }111 112 }113 return 0;114 }115 116 int main()117 {118 int i,j;119 char ch;120 while(cin>>ch)121 {122 if(ch=='x')123 {124 start.ma[0]=9;125 start.x=0;126 }127 else128 start.ma[0]=ch-'0';129 for( i=1;i<9;i++)130 {131 cin>>ch;132 if(ch=='x')133 {134 start.ma[i]=9;135 start.x=i;136 }137 else138 start.ma[i]=ch-'0';139 }140 start.ans1=hash(start.ma);141 memset(visited,0,sizeof(visited));142 if(bfs())143 cout<<path<<endl;144 else145 146 printf("unsolvable\n");147 148 }149 return 0;150 }
但是 hdu 1043 多项数据输入,如果采用正向搜索,绝对超时。
反向搜索,把所有情况打表出来。
hash+ 打表+广搜
代码如下:
#include<iostream>#include<stdlib.h>#include<stdio.h>#include<math.h>#include<string.h>#include<string>#include<queue>#include<algorithm>#define N 363000 // 9! = 362880using namespace std;struct node{ int ma[9]; int ans1; //哈希值 int x; // 记录x可移动的位置 string path;};int visited[N];string path[N];node start;int end = 0; // 123456789对应的哈希值int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; // 上-右-下-左char index[5]="dlur"; // 下-左-上-右 , 反向搜索,用于打表int fact[] = {1, 1, 2, 6, 24,120 ,720, 5040, 40320};int hash(int *s) // 返回每个排列的哈希值{ int sum=0; for(int i=0;i< 9;i++) { int num=0; // 计算 第i位数的逆序数 for(int j=0;j<i;j++) if(s[i]<s[j]) num++; sum+= num * fact[i]; // sum的取值范围是 0---9!-1 } return sum;}//广度优先搜索 多项输入,打表,否则 超时void bfs(){ memset(visited,0,sizeof(visited)); node now,next; int x ,y,ans; for(int i=0;i<9;i++) now.ma[i]=i+1; now.x=8; now.ans1=end; now.path=""; queue<node>q; q.push(now); path[end]=""; while(!q.empty()) { now =q.front(); //取出队列头的顶点,设为now q.pop(); x= now.x /3; y= now.x %3; for(int i=0;i<4;i++) { int tx= x+dir[i][0]; int ty= y+dir[i][1]; if(ty<0 || ty>2 || tx<0 || tx>2) continue; next=now; // next 为 now的邻接顶点 next.x= tx*3+ty; next.ma[now.x] = now.ma[next.x]; next.ma[next.x] = 9; next.ans1 = hash(next.ma); if(!visited[next.ans1] ) { visited[next.ans1]=1; next.path=index[i]+next.path; //字符串反向存储,然后输出 q.push(next); path[next.ans1]=next.path; // 打表 } } }}int main(){ int i,j; char ch; bfs(); while(cin>>ch) { if(ch=='x') { start.ma[0]=9; start.x=0; } else start.ma[0]=ch-'0'; for( i=1;i<9;i++) { cin>>ch; if(ch=='x') { start.ma[i]=9; start.x=i; } else start.ma[i]=ch-'0'; } start.ans1=hash(start.ma); if(visited[start.ans1]) // 在表里的点 cout<<path[start.ans1]<<endl; else printf("unsolvable\n"); } return 0;}
三:
hdu 1043 A* +哈密顿距离+ hash+剪枝 + 堆
代码如下:
#include<iostream>#include<stdlib.h>#include<stdio.h>#include<math.h>#include<string.h>#include<string>#include<queue>#include<algorithm>#define N 363000 // 9! = 362880using namespace std;struct node{ int ma[9]; int ans1; //哈希值 int x; // 记录x可移动的位置,记为9 int f; // 估价函数 int g; // 深度 string path; bool operator <(const node & a)const{ return f>a.f; //优先访问估价函数值f较小的节点 }};int visited[N];string path;node start;int end = 0; // 123456789对应的哈希值int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; // 上-右-下-左char index[5]="urdl";// 哈希表,排列逆序,用于判重int fact[] = {1, 1, 2, 6, 24,120 ,720, 5040, 40320}; // 康托展开数列 //0! 1! 2! 3! 4! 5! 6! 7! 8!int hash(int *s) // 返回每个排列的哈希值{ int sum=0; for(int i=0;i< 9;i++) { int num=0; // 计算 第i位数的逆序数 for(int j=0;j<i;j++) if(s[i]<s[j]) num++; sum+= num * fact[i]; // sum的取值范围是 0---9!-1 } return sum;}int ABS(int x){return x>0?x:(-x);} //求绝对值int h_juli(int *s) // 不算x时的 曼哈顿距离启发函数,计算的是 从第n个点到目标点的最小代价{ int tx,ty,endx,endy,tmp; // 逆序搜索,从目标状态为起点 int sum=0; for(int i=0;i<9;i++) { if(s[i]== 9) continue; tmp=s[i]; tx= i /3; ty= i %3 ; endx = (tmp-1)/3; endy = (tmp-1)%3; sum+=ABS(tx-endx) + ABS(ty- endy); } return sum;}//广度优先搜索int bfs(){ priority_queue<node>q; node now,next; int x ,y,ans; now= start; now.ans1=hash(now.ma); now.path=""; if(now.ans1 == end){ path=now.path; return 1; } visited[now.ans1] =1; // 访问起始节点 now.g = 0; // 深度置为0 now.f = h_juli(now.ma); q.push(now); //将顶点now压入队列 while(!q.empty()) { now =q.top(); //取出队列头的顶点,设为now q.pop(); x= now.x /3; y= now.x %3; for(int i=0;i<4;i++) { int tx= x+dir[i][0]; int ty= y+dir[i][1]; if(ty<0 || ty>2 || tx<0 || tx>2) continue; next=now; // next 为 now的邻接顶点 next.x= tx*3+ty; next.ma[now.x] = now.ma[next.x]; next.ma[next.x] = 9; ans = hash(next.ma); if(!visited[ans] ) //且next没有访问过,访问next顶点,对next赋值,并将next加入队列 { visited[ans]=1; next.ans1=ans; next.g++; next.f= next.g+h_juli(next.ma); next.path+=index[i]; if(next.ans1 == end){ path=next.path; return 1; } q.push(next); } } } return 0;}int check(int *s) // 剪枝{ int i, j,num=0; for( i=0;i<9;i++) { if(s[i] == 9) continue; for(j=0;j<i;j++) { if(s[j] ==9) continue; if(s[j] >s[i]) num++; } } return num&1; // 逆序数为偶数,返回0,否则返回1}int main(){ int i,j; char ch; while(cin>>ch) { if(ch=='x') { start.ma[0]=9; start.x=0; } else start.ma[0]=ch-'0'; for( i=1;i<9;i++) { cin>>ch; if(ch=='x') { start.ma[i]=9; start.x=i; } else start.ma[i]=ch-'0'; } if(check(start.ma)) {puts("unsolvable"); continue;} // 逆序数 为偶数,可达, 逆序数为奇数,不可达 start.ans1=hash(start.ma); memset(visited,0,sizeof(visited)); if(bfs()) cout<<path<<endl; else printf("unsolvable\n"); } return 0;}
排列哈希函数判重,参见:
http://blog.csdn.net/tiaotiaoyly/article/details/1720453
哈密顿距离 为 两个点 (x1,y1) (x2,y2) 距离= | x1 - x2| +| y1- y2|
A*算法
f(n)= g(n) + h(n) f(n)为估价函数 h(n) 为启发函数,是哈密顿距离 , g(n) 为节点n的深度
0 0
- 八数码难题 hdu1043/ poj1077
- poj1077 hdu1043 Eight 八数码问题
- Poj1077/HDU1043(A*搜索)八数码问题
- 八数码与IDA*问题 HDU1043&&POJ1077
- POJ1077、HDU1043 Eight 八数码问题:双向BFS、A*
- POJ1077 HDU1043 Eight 八数码 (A*+康托展开)
- POJ1077 HDU1043 Eight 八数码第四境界 双向广搜 康托展开 逆康托
- POJ1077&HDU1043 Eight 八数码第八境界 IDA* hash 康托展开 奇偶剪枝
- hdu1043 八数码问题
- hdu1043【八数码】【A*】
- POJ1077 八数码问题
- POJ1077&HDU1043 Eight 八数码第七境界 AStar hash 康托展开 最小堆优化 奇偶剪枝
- HDU1043 eight 八数码问题
- HDU1043 Eight 八数码问题
- hdu1043八数码问题解题报告
- hdu1043 Eight (八数码问题,多种解法)
- POJ1077(经典的八数码问题)
- POJ1077八数码问题哈希,bfs
- hdu 1027 排列生成器
- hdu 1020 简单的字符串处理
- hdu 1039 连续字符串处理
- hdu 1048 字符串
- hdu 1073 字符串函数的应用
- 八数码难题 hdu1043/ poj1077
- 九度oj 1551 二分 + 精度
- 移动APP开发者近百万 推广费用高成功率不足1%
- hdu 1299 整数分解
- hdu 1452 因子和 + 逆元素+ 快速幂
- hdu 1215 数论 +打表
- hdu 数论+ 欧拉函数 1787
- hdu 2136 数论+筛选质数+打表
- hdu 1796 容斥原理