hdu1043 Eight 康拓展开+bfs打表
来源:互联网 发布:java中文乱码怎么解决 编辑:程序博客网 时间:2024/05/21 07:57
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
经典的八数码,一般做法直接bfs,肯定tle。应该用A*剪枝或者打表,我用的是打表,打表更快点。
我的思路是以最终状态为起点进行bfs,同时开个结构体数组来记忆bfs过程中的状态(方向,这个八数码状态的上个状态的结构体数组下标),最终可以回溯打印路径。 同时给定一种状态要能找到他对应的结构体数组的下标,所以需要再开个数组存每种状态的记忆数组的下标。 同时在回溯的时候方向是反着的,因为我是以末状态搜起始状态的,本来是左,倒过来就是右了,所以在存方向的时候,需要变换一下。
八数码的状态用康拓值来映射
代码:
#include<cstdio>#include<cstring>#include<string>#include<queue>#include<cmath>#include<vector>#include<map>#include<stack>#include<iostream>#include<algorithm>using namespace std;#define ll long long#define inf 0x3f3f3f3f#define scanfprint() freopen("input.txt","r",stdin)#define printfprint() freopen("output.txt","w",stdout)#define mem(a,b) memset(a,b,sizeof(a))const int spot=1000+10;const int edge=100000+10;const int maxn=362880+10;const double pi=acos(-1.0);const int mod=1e9+7;const double ips=0.000001;const int c_n=9;bool c_flag[c_n+10];int c_a[c_n+10],fact[15]= {0,1,1,2,6,24,120,720,5040,40320,362880},m[maxn],num=0; //m为给定康拓值映射的存储路径的结构体下标char str[10];struct stu1//打表存储bfs过程的结构体{ int pre; //上一个状态的下标 char dir; //方向} memory[maxn]; struct stu2{ int c_v,num,coor; //分别对应 康拓值,打表的下标,八数码里x的下标} s,t;bool flag[maxn]; //int cantor() //康拓展开 c_a[1]到c_a[n]表示一个全排列,返回的ans表示康拓值(从0开始){ mem(c_flag,0); int i,j,sum=0,ans=0,k; for(i=1,k=c_n; i<=c_n; i++,k--) { sum=0; for(j=c_a[i]-1; j>=1; j--) { if(!c_flag[j]) sum++; } c_flag[c_a[i]]=1,ans+=sum*fact[k]; } return ans;}void inverse_cantor(int m) //康拓逆展开 传入的m是康拓值(从0开始),最终的c_a[1]到c_a[n]是m对应的排列{ mem(c_flag,0); int i,j,k,sum; for(i=1,k=c_n; i<=c_n; i++,k--) { sum=m/fact[k]+1; for(j=1; j<=c_n; j++) { if(!c_flag[j]) sum--; if(!sum) break; } c_a[i]=j,c_flag[j]=1,m%=fact[k]; }}void bfs(){ int i,temp; s.c_v=0,s.num=0,s.coor=9; flag[s.c_v]=1; queue<stu2>q; q.push(s); while(!q.empty()) { s=q.front(); q.pop(); inverse_cantor(s.c_v); //逆康拓,还原八数码的状态 for(i=0; i<4; i++) //四个方向 下 左 右上 { if(!i) //下 { if(s.coor<7) { swap(c_a[s.coor],c_a[s.coor+3]); //交换位置 t.c_v=cantor(); //得到状态所对应的康拓值 if(!flag[t.c_v]) { t.coor=s.coor+3,t.num=++num; //9位置变换, memory[num].dir='u',memory[num].pre=s.num; // 方向需要调换一下,下上互换,左右互换 m[t.c_v]=num; //得到康拓值对应的存储路径结构体数组的下标 flag[t.c_v]=1; //标记 q.push(t); } swap(c_a[s.coor],c_a[s.coor+3]); } } if(i==1) //左 { if(s.coor!=1&&s.coor!=4&&s.coor!=7) { swap(c_a[s.coor],c_a[s.coor-1]); t.c_v=cantor(); if(!flag[t.c_v]) { t.coor=s.coor-1,t.num=++num; memory[num].dir='r',memory[num].pre=s.num; m[t.c_v]=num; flag[t.c_v]=1; q.push(t); } swap(c_a[s.coor],c_a[s.coor-1]); } } if(i==2) //右 { if(s.coor!=3&&s.coor!=6&&s.coor!=9) { swap(c_a[s.coor],c_a[s.coor+1]); t.c_v=cantor(); if(!flag[t.c_v]) { t.coor=s.coor+1,t.num=++num; memory[num].dir='l',memory[num].pre=s.num; m[t.c_v]=num; flag[t.c_v]=1; q.push(t); } swap(c_a[s.coor],c_a[s.coor+1]); } } if(i==3)//上 { if(s.coor>3) { swap(c_a[s.coor],c_a[s.coor-3]); t.c_v=cantor(); if(!flag[t.c_v]) { t.coor=s.coor-3,t.num=++num; memory[num].dir='d',memory[num].pre=s.num; m[t.c_v]=num; flag[t.c_v]=1; q.push(t); } swap(c_a[s.coor],c_a[s.coor-3]); } } } }}void deal_cin(int in){ if(str[in]=='x') c_a[in]=9; else c_a[in]=str[in]-'0';}void print(int n) //回溯打印路径{ if(!n) return ; printf("%c",memory[n].dir); print(memory[n].pre);}int main(){ int i,j; for(i=1; i<=9; i++) c_a[i]=i; bfs(); //打表 while(cin>>str[1]) { deal_cin(1); for(i=2; i<=9; i++) cin>>str[i],deal_cin(i); int ans=cantor(); if(flag[ans]) print(m[ans]); else printf("unsolvable"); puts(""); } return 0;}
康拓,逆康拓模板:
const int c_n=9;bool c_flag[c_n+10];int c_a[c_n+10],fact[15]= {0,1,1,2,6,24,120,720,5040,40320,362880};int cantor() //康拓展开 c_a[1]到c_a[n]表示一个全排列,返回的ans表示康拓值(从0开始){ mem(c_flag,0); int i,j,sum=0,ans=0,k; for(i=1,k=c_n; i<=c_n; i++,k--) { sum=0; for(j=c_a[i]-1; j>=1; j--) { if(!c_flag[j]) sum++; } c_flag[c_a[i]]=1,ans+=sum*fact[k]; } return ans;}void inverse_cantor(int m) //康拓逆展开 传入的m是康拓值(从0开始),最终的c_a[1]到c_a[n]是m对应的排列{ mem(c_flag,0); int i,j,k,sum; for(i=1,k=c_n; i<=c_n; i++,k--) { sum=m/fact[k]+1; for(j=1; j<=c_n; j++) { if(!c_flag[j]) sum--; if(!sum) break; } c_a[i]=j,c_flag[j]=1,m%=fact[k]; }}
0 0
- hdu1043 Eight 康拓展开+bfs打表
- HDU1043:Eight HDU3567:Eight II(康拓展开+bfs搜索)
- hdu1043 bfs 康拓展开
- hdu1043 Eight(A*/双向BFS/单项BFS打表+康托展开)
- HDOJ 题目1043 Eight(单向BFS,康拓展开,打表)
- HDU1043 Eight[bfs]
- HDU 1043 Eight(BFS+康拓展开)
- A*算法 hdu1043 Eight 人工智能算法, 还有康拓展开得hash值
- POJ 1077 Eight(康拓展开 BFS 双向BFS)
- POJ 1077 Eight BFS + 康拓展开式
- hdu3567 Eight II 康拓展开+打表+路径回溯+映射
- hdu1430(康拓展开+bfs打表)
- hdu 1430 bfs + 打表 + 康拓展开
- hdu1043 Eight —— 反向bfs+康拓
- HDU1043:Eight(A*+康托)
- HDU1043:Eight(A*+康托)
- HDU1043:Eight(A*+康托)
- hdu1043 Eight
- 文件读取和写入
- 详解call()和apply()
- 早产的2016年终总结
- Java常用类
- bind源码解析
- hdu1043 Eight 康拓展开+bfs打表
- Windows下保存git 用户名和密码
- 网络连接请求
- 树状数组
- 李白打酒
- 深入理解 Java G1 垃圾收集器
- window下与Ubuntu14 虚拟机的samba共享
- extern "c"用法解析
- Android异步任务机制—AsyncTask