8数码 BFS

POJ 1077

下面的代码总是TLE。。。

1. 使用STL set

#include <cstdio> #include <cstring> #include <queue> #include <stack> #include <set> using namespace std; class S { public: char c[9]; int op; S* p; S(char *c1 = 0, int op = 0, S* p = 0):op(op),p(p){ if(c1) { /* for(int i = 0; i < 9; i++) { c[i] = c1[i]; } */ memcpy(c, c1, 9); } } bool operator==(char* c1) { /* for(int i = 0; i < 9; i++) { if (c[i] != c1[i]) { return false; } } return true; */ return memcmp(c, c1, 9) == 0; } /* bool operator==(S& s) { return (*this) == (s.c); } */ bool operator<(const S& s) const { /* for(int i = 0; i < 9; i++) { if(c[i] < s.c[i]) { return true; } else if(c[i] > s.c[i]) { return false; } } return false; */ return memcmp(c, s.c, 9) < 0; } }; queue<S*> q; set<S> hash; S* getState(S *s, int op) { int loc = -1; for(int i = 0; i < 9; i++) { if(s->c[i] == 'x') { loc = i; break; } } int x = loc / 3; int y = loc % 3; //cout << "loc " << loc << " -> " << x << ", " << y << endl; int nx, ny; S* ns = 0; switch(op) { case 0: // u nx = x - 1; ny = y; break; case 1: // d nx = x + 1; ny = y; break; case 2: // l nx = x; ny = y - 1; break; case 3: // r nx = x; ny = y + 1; break; } if (nx >= 0 && nx <= 2 && ny >= 0 && ny <= 2) { ns = new S(s->c, op, s); // perform the operation ns->c[x * 3 + y] = ns->c[nx * 3 + ny]; ns->c[nx * 3 + ny] = 'x'; } return ns; } void print(S s) { for(int i = 0; i < 9; i++) { //cout << s.c[i]; printf("%c", s.c[i]); } //cout << endl; printf("/n"); } char OP[4] = {'u', 'd', 'l', 'r'}; /* void print(int op) { switch(op) { case 0: cout << "u"; break; case 1: cout << "d"; break; case 2: cout << "l"; break; case 3: cout << "r"; break; } } */ char C[9] = {'1', '2', '3', '4', '5', '6', '7', '8', 'x'}; void BFS() { while(!q.empty()) { S* ps = q.front(); q.pop(); if(*ps == C) { stack<int> st; while(ps->p) { st.push(ps->op); ps = ps->p; } while(!st.empty()) { printf("%c", OP[st.top()]); st.pop(); } //cout << endl; printf("/n"); return; } for(int i = 0; i < 4; i++) { S *ns = getState(ps, i); if(ns && (hash.find(*ns) == hash.end())) { //print(*ns); hash.insert(*ns); q.push(ns); } } } } int main() { char c[9]; for(int i = 0; i < 9; i++) { //cin >> c[i]; scanf("%c ", &(c[i])); } S s(c, 0, 0); hash.insert(s); //cout << (*hash.find(s1)).op << endl; //cout << (hash.find(s1) != hash.end()) << endl; q.push(&s); BFS(); }

2. 使用hash

#include <cstdio> #include <cstring> #include <queue> #include <stack> using namespace std; class S { public: char c[9]; int op; S* p; S(char *c1 = 0, int op = 0, S* p = 0):op(op),p(p){ if(c1) { memcpy(c, c1, 9); } } bool operator==(char* c1) { return memcmp(c, c1, 9) == 0; } bool operator==(S& s1) { return (*this) == s1.c; } bool operator<(const S& s) const { return memcmp(c, s.c, 9) < 0; } }; void print(S s) { for(int i = 0; i < 9; i++) { printf("%c", s.c[i]); } printf("/n"); } const int MAXSTATE = 1000000; const int MAXHASHSIZE = 1000003; int head[MAXHASHSIZE], next[MAXSTATE]; S* st[MAXSTATE]; int sno = 0; void init_lookup_table() { memset(head, 0, sizeof(head)); } int hash(S& s) { int v = 0; for(int i = 0; i < 9; i++) v = v * 10 + s.c[i]; return v % MAXHASHSIZE; } int try_to_insert(S *s) { //printf("trying insert %dth state : ", s); //print(*st[s]); int h = hash(*s); int u = head[h]; while(u) { if((*st[u]) == *s) return 0; u = next[u]; } next[sno] = head[h]; head[h] = sno; st[sno++] = s; return 1; } queue<S*> q; S* getState(S *s, int op) { int loc = -1; for(int i = 0; i < 9; i++) { if(s->c[i] == '0') { loc = i; break; } } int x = loc / 3; int y = loc % 3; int nx, ny; S* ns = 0; switch(op) { case 0: // u nx = x - 1; ny = y; break; case 1: // d nx = x + 1; ny = y; break; case 2: // l nx = x; ny = y - 1; break; case 3: // r nx = x; ny = y + 1; break; } if (nx >= 0 && nx <= 2 && ny >= 0 && ny <= 2) { ns = new S(s->c, op, s); // perform the operation ns->c[x * 3 + y] = ns->c[nx * 3 + ny]; ns->c[nx * 3 + ny] = '0'; } return ns; } char OP[4] = {'u', 'd', 'l', 'r'}; char C[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '0'}; void BFS() { while(!q.empty()) { S* ps = q.front(); q.pop(); if(*ps == C) { stack<int> st; while(ps->p) { st.push(ps->op); ps = ps->p; } while(!st.empty()) { printf("%c", OP[st.top()]); st.pop(); } printf("/n"); return; } for(int i = 0; i < 4; i++) { S *ns = getState(ps, i); if(ns) { if(try_to_insert(ns)) { q.push(ns); } } } } } int main() { char c[9]; for(int i = 0; i < 9; i++) { scanf("%c ", &(c[i])); if(c[i] == 'x') { c[i] = '0'; } } S s(c, 0, 0); st[sno++] = &s; q.push(&s); BFS(); }

测试结果:

/home/a/j/nomad2:cat input 8 6 7 2 5 4 3 x 1 /home/a/j/nomad2:time cat input |./a.out uulddrruuldldrruuldldrruullddrr real 0m0.284s user 0m0.239s sys 0m0.034s

注:网上的一个hash的ac代码

#include<iostream> #include<string> #include<cstdlib> #include<cstring> #include<cstdio> #include<set> #include<algorithm> using namespace std; const int MAXSTATE=1000000; const int MAXHASHSIZE=1000003; //定义哈希表大小 typedef int state[9]; //定义"状态"类型 state st[MAXSTATE],goal={1,2,3,4,5,6,7,8,0}; int head[MAXHASHSIZE]; int next[MAXSTATE]; int dir[MAXSTATE]; int p[MAXSTATE][2]; //p[s][0]存放父亲节点,p[s][1]存放移动方向 int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; char name[4]={'u','d','l','r'}; void Init() //初始化哈希表表头 { memset(head,0,sizeof(head)); } int Hash(state & s) //哈希函数 { int i,v=0; for(i=0;i<9;i++) v=v*10+s[i]; return v%MAXHASHSIZE; } int Hash_Search(int s) //判重,即判断状态s是否已近拓展过 { int h,u; h=Hash(st[s]); u=head[h]; //从表头开始查找 while(u) { if(memcmp(st[u],st[s],sizeof(st[s]))==0) //状态st[s]已经存在 return 0; u=next[u]; //否则继续查找 } next[s]=head[h]; //插入到链表中 head[h]=s; return 1; } int BFS() { int x,y,z,d,newx,newy,newz,front,rear; Init(); front=1; rear=2; p[front][0]=-1; while(front<rear) { state & s=st[front]; //用引用简化代码 if(memcmp(goal,s,sizeof(s))==0) //找到目标状态,成功返回 return front; for(z=0;z<9;z++) //找0的位置,将输入中的'x'用0来表示 if(s[z]==0) break; x=z/3; y=z%3; for(d=0;d<4;d++) { newx=x+dx[d]; newy=y+dy[d]; if(newx>=0&&newx<3&&newy>=0&&newy<3) //移动不超出范围 { newz=3*newx+newy; state & t=st[rear]; memcpy(&t,&s,sizeof(s)); //扩展新节点 t[newz]=s[z]; t[z]=s[newz]; p[rear][0]=front; //存储父亲节点 p[rear][1]=d; //存储该步移动方向 if(Hash_Search(rear)) //如果成功插入查找表,修改队尾指针 rear++; } } front++; //扩展完毕再修改队首指针 } return 0; //移动失败 } void Print_Path(int t) //打印移动路线 { int i=0; while(p[t][0]!=-1) { dir[i++]=p[t][1]; t=p[t][0]; } while(i--) printf("%c",name[dir[i]]); printf("/n"); } int main() { int i,ans,len,j; char ss[30]; while(gets(ss)!=NULL) { len=strlen(ss);j=0; for(i=0;i<len;i++) if(ss[i]!=' ') { if(ss[i]!='x') //将'x'用0代替 st[1][j++]=ss[i]-'0'; else st[1][j++]=0; } ans=BFS(); if(ans>1) Print_Path(ans); else //此时不存在移动方案 printf("impossibile/n"); } return 0; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值