HDOJ 1043 Eight

                用了五天左右做了一下八数码的问题,所谓的八重境界也就是实现了四种而已,但是心里已经感觉实在坐不下去了,就这样总结一下吧。八数码问题使用了两点辅助工具。第一是曼哈顿距离,用来作为A*的h函数以及IDA*的剪枝。第二是康拓展开,用来标识已经遍历过的状态。第三是逆序数,作为问题的剪枝。参考代码中的运行时间和内存大小仅供参考吧,毕竟使用了STL的栈,速度方面会有影响。毕竟每次末尾还要做清理工作。其实用数组代替效率会更高些,但是内存也会消耗更厉害些。

方法一:预处理+反向宽度优先搜索       Exe.Time    562MS    Exe.Memory    19592K

View Code
 1 //#include<fstream>   
2 #include <iostream>
3 #include<string>
4 #include<queue>
5 using namespace std;
6 #define N 9
7 #define NMAX 362885
8
9 struct Point{
10 char eightMap[N];
11 int position;
12 string path;
13 };
14 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
15 const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
16 const char option[4]={'u','l','d','r'};
17 bool visited[NMAX];
18 string inversionPath[NMAX];
19
20 inline int cantor(Point p){
21 int ans=0;
22 for(int i=0;i<N;i++)
23 {
24 int cnt=0;
25 for(int k=i+1;k<N;k++)
26 {
27 if(p.eightMap[k]<p.eightMap[i])
28 cnt++;
29 }
30 ans+=fac[8-i]*cnt;
31 }
32 return ans;
33 }
34
35 bool bfs(){
36 int row,col,cantorValue;
37 memset(visited,false,sizeof(visited));
38 Point startPoint;
39 for (int i=1;i<N;i++)
40 startPoint.eightMap[i-1]=i+'0';
41 startPoint.eightMap[N-1]='x';
42 startPoint.position=N-1;
43 startPoint.path="";
44 visited[0]=true;
45 queue<Point> que;
46 que.push(startPoint);
47 while(!que.empty()){
48 Point p=que.front();
49 que.pop();
50 for(int i=0;i<4;i++){
51 row=p.position/3+dir[i][0];
52 col=p.position%3+dir[i][1];
53 if(row<0||col<0||row>=3||col>=3) continue;
54 Point newPoint(p);
55 newPoint.eightMap[newPoint.position]=newPoint.eightMap[col+row*3];
56 newPoint.position=col+row*3;
57 newPoint.eightMap[newPoint.position]='x';
58 cantorValue=cantor(newPoint);
59 if(visited[cantorValue]) continue;
60 visited[cantorValue]=true;
61 newPoint.path+=option[i];
62 inversionPath[cantorValue]=newPoint.path;
63 que.push(newPoint);
64 }
65 }
66 return false;
67 }
68
69
70 int main(){
71 //fstream cin("Eight.txt");
72 Point startPoint;
73 int startCantor;
74 bfs();
75 while(cin>>startPoint.eightMap[0])
76 {
77 if(startPoint.eightMap[0]=='x')
78 startPoint.position=0;
79 for(int i=1;i<9;i++)
80 {
81 cin>>startPoint.eightMap[i];
82 if(startPoint.eightMap[i]=='x')
83 startPoint.position=i;
84 }
85 startCantor=cantor(startPoint);
86 if(visited[startCantor])
87 {
88 for (int i=inversionPath[startCantor].size()-1;i>=0;i--)
89 cout<<inversionPath[startCantor][i];
90 cout<<endl;
91 }
92 else
93 {
94 cout<<"unsolvable"<<endl;
95 }
96 }
97 return 0;
98 }

方法二:双向宽度优先搜索       Exe.Time 1046MS         Exe.Memory   10784K

View Code
  1 //#include<fstream>  
2 #include <iostream>
3 #include<string>
4 #include<queue>
5 #include <algorithm>
6 using namespace std;
7 #define N 9
8 #define NMAX 362885
9
10 struct Point{
11 char eightMap[N];
12 int position;
13 string path;
14 };
15 Point startPoint;
16 queue<Point> que,inversionQue;
17
18 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
19 const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
20 const char option[4]={'d','r','u','l'};
21 const char inversionOption[4]={'u','l','d','r'};
22 char visited[NMAX];
23 string path[NMAX];
24 string result;
25 bool flag;
26
27 inline int cantor(Point p){
28 int ans=0;
29 for(int i=0;i<N;i++)
30 {
31 int cnt=0;
32 for(int k=i+1;k<N;k++)
33 {
34 if(p.eightMap[k]<p.eightMap[i])
35 cnt++;
36 }
37 ans+=fac[8-i]*cnt;
38 }
39 return ans;
40 }
41 inline bool inversionNumberCheck(){
42 int cnt=0;
43 for(int i=0;i<N;i++){
44 if(startPoint.eightMap[i]=='x') continue;
45 for(int k=i-1;k>=0;k--){
46 if(startPoint.eightMap[k]=='x') continue;
47 if(startPoint.eightMap[k]>startPoint.eightMap[i])
48 cnt++;
49 }
50 }
51 return cnt&1;
52 }
53 void bfs(){
54 int row,col,cantorValue;
55 Point p=que.front();
56 que.pop();
57 for(int i=0;i<4;i++)
58 {
59 row=p.position/3+dir[i][0];
60 col=p.position%3+dir[i][1];
61 if(row<0||col<0||row>=3||col>=3) continue;
62 Point newPoint(p);
63 newPoint.eightMap[newPoint.position]=newPoint.eightMap[col+row*3];
64 newPoint.position=col+row*3;
65 newPoint.eightMap[newPoint.position]='x';
66 cantorcantorValue=cantor(newPoint);
67 if(visited[cantorValue]==1) continue;
68 newPoint.path+=option[i];
69 if(visited[cantorValue]==2)
70 {
71 flag=false;
72 reverse(path[cantorValue].begin(),path[cantorValue].end());
73 result=newPoint.path+path[cantorValue];
74 return ;
75 }
76 path[cantorValue]=newPoint.path;
77 visited[cantorValue]=1;
78 que.push(newPoint);
79 }
80 }
81 void inversionBfs(){
82 int row,col,cantorValue;
83 Point p=inversionQue.front();
84 inversionQue.pop();
85 for(int i=0;i<4;i++)
86 {
87 row=p.position/3+dir[i][0];
88 col=p.position%3+dir[i][1];
89 if(row<0||col<0||row>=3||col>=3) continue;
90 Point newPoint(p);
91 newPoint.eightMap[newPoint.position]=newPoint.eightMap[col+row*3];
92 newPoint.position=col+row*3;
93 newPoint.eightMap[newPoint.position]='x';
94 cantorcantorValue=cantor(newPoint);
95 if(visited[cantorValue]==2) continue;
96 newPoint.path+=inversionOption[i];
97 if(visited[cantorValue]==1)
98 {
99 flag=false;
100 reverse(newPoint.path.begin(),newPoint.path.end());
101 result=path[cantorValue]+newPoint.path;
102 return ;
103 }
104 path[cantorValue]=newPoint.path;
105 visited[cantorValue]=2;
106 inversionQue.push(newPoint);
107 }
108 }
109
110 int main(){
111 //fstream cin("Eight.txt");
112 Point endPoint;
113 int cnt;
114 for (int i=1;i<N;i++)
115 endPoint.eightMap[i-1]=i+'0';
116 endPoint.eightMap[N-1]='x';
117 endPoint.position=N-1;
118 endPoint.path="";
119 while(cin>>startPoint.eightMap[0])
120 {
121 if(startPoint.eightMap[0]=='x')
122 startPoint.position=0;
123 for(int i=1;i<9;i++)
124 {
125 cin>>startPoint.eightMap[i];
126 if(startPoint.eightMap[i]=='x')
127 startPoint.position=i;
128 }
129 if(inversionNumberCheck()){
130 cout<<"unsolvable"<<endl;
131 continue;
132 }
133 int startCantor=cantor(startPoint);
134 if(startCantor==0)
135 {
136 cout<<endl;
137 continue;
138 }
139 memset(visited,false,sizeof(visited));
140 while(!inversionQue.empty())
141 inversionQue.pop();
142 while(!que.empty())
143 que.pop();
144 flag=true;
145 inversionQue.push(endPoint);
146 visited[0]=2;
147 que.push(startPoint);
148 visited[startCantor]=1;
149 while(flag)
150 {
151 cnt=inversionQue.size();
152 while(cnt--&&flag)
153 inversionBfs();
154 cnt=que.size();
155 while(cnt--&&flag)
156 bfs();
157 }
158 cout<<result<<endl;
159 }
160 return 0;
161 }

方法三:A-Star算法           Exe.Time  1078MS          Exe.Memory   2636K

View Code
  1 //#include<fstream>   
2 #include <iostream>
3 #include<string>
4 #include<queue>
5 #include <stack>
6 using namespace std;
7 #define N 9
8
9 struct Point{
10 char eightMap[N];
11 int position;
12 int g,f;
13 friend bool operator< (const Point& a,const Point& b){
14 return a.f>b.f;
15 }
16 }startPoint;
17 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
18 const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
19 const char option[4]={'d','r','u','l'};
20 bool visited[363000];
21 int pre[363000];
22 char op[363000];
23 stack<char> stk;
24
25 inline int cantor(Point p){
26 int ans=0;
27 for(int i=0;i<N;i++)
28 {
29 int cnt=0;
30 for(int k=i+1;k<N;k++)
31 {
32 if(p.eightMap[k]<p.eightMap[i])
33 cnt++;
34 }
35 ans+=fac[8-i]*cnt;
36 }
37 return ans;
38 }
39
40 inline int ABS(int x){return x<0?-x:x;}
41 inline int h(Point p){
42 int val=0;
43 for(int i=0;i<N;i++){
44 if(p.eightMap[i]=='x') continue;
45 int c=p.eightMap[i]-'1';
46 val+=ABS(c/3-i/3)+ABS(c%3-i%3);
47 }
48 return val;
49 }
50
51 bool bfs(){
52 int row,col,cantorValue;
53 memset(visited,false,sizeof(visited));
54 priority_queue<Point> que;
55 que.push(startPoint);
56 while(!que.empty()){
57 Point p=que.top();
58 que.pop();
59 for(int i=0;i<4;i++){
60 row=p.position/3+dir[i][0];
61 col=p.position%3+dir[i][1];
62 if(row<0||col<0||row>=3||col>=3) continue;
63 Point newPoint(p);
64 newPoint.eightMap[newPoint.position]=newPoint.eightMap[col+row*3];
65 newPoint.position=col+row*3;
66 newPoint.eightMap[newPoint.position]='x';
67 cantorValue=cantor(newPoint);
68 if(visited[cantorValue]) continue;
69 visited[cantorValue]=true;
70 newPoint.g++;
71 newPoint.f=newPoint.g+h(newPoint);
72 pre[cantorValue]=cantor(p);
73 op[cantorValue]=option[i];
74 if(cantorValue==0) return true;
75 que.push(newPoint);
76 }
77 }
78 return false;
79 }
80
81 inline bool inversionNumberCheck(){
82 int cnt=0;
83 for(int i=0;i<N;i++){
84 if(startPoint.eightMap[i]=='x') continue;
85 for(int k=i-1;k>=0;k--){
86 if(startPoint.eightMap[k]=='x') continue;
87 if(startPoint.eightMap[k]>startPoint.eightMap[i])
88 cnt++;
89 }
90 }
91 return cnt&1;
92 }
93 int main(){
94 //fstream cin("Eight.txt");
95 while(cin>>startPoint.eightMap[0])
96 {
97 if(startPoint.eightMap[0]=='x')
98 startPoint.position=0;
99 for(int i=1;i<9;i++)
100 {
101 cin>>startPoint.eightMap[i];
102 if(startPoint.eightMap[i]=='x')
103 startPoint.position=i;
104 }
105 if(inversionNumberCheck()){
106 cout<<"unsolvable"<<endl;
107 continue;
108 }
109 startPoint.g=0;
110 startPoint.f=h(startPoint);
111 int startCantor=cantor(startPoint);
112 bfs();
113 int index=0;
114 while(index!=startCantor){
115 stk.push(op[index]);
116 index=pre[index];
117 }
118 while(!stk.empty())
119 {
120 cout<<stk.top();
121 stk.pop();
122 }
123 cout<<endl;
124 }
125 }

方法四:IDA*算法              Exe.Time    2609MS              Exe.Memory   952K

View Code
  1 //#include<fstream>   
2 #include <iostream>
3 using namespace std;
4 #define N 9
5
6 struct Point{
7 char eightMap[N];
8 int position;
9 }startPoint;
10 const int fac[]={1,1,2,6,24,120,720,5040,40320};//康托序列
11 const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
12 const char option[4]={'d','r','u','l'};
13 bool visited[362885];
14 char op[362885];
15 int deep;
16 bool flag;
17
18 inline int cantor(Point p){
19 int ans=0;
20 for(int i=0;i<N;i++)
21 {
22 int cnt=0;
23 for(int k=i+1;k<N;k++)
24 {
25 if(p.eightMap[k]<p.eightMap[i])
26 cnt++;
27 }
28 ans+=fac[8-i]*cnt;
29 }
30 return ans;
31 }
32
33 inline int ABS(int x){return x<0?-x:x;}
34 inline int h(Point p){
35 int val=0;
36 for(int i=0;i<N;i++){
37 if(p.eightMap[i]=='x') continue;
38 int c=p.eightMap[i]-'1';
39 val+=ABS(c/3-i/3)+ABS(c%3-i%3);
40 }
41 return val;
42 }
43
44 void dfs(int d){
45 int check=h(startPoint);
46 if(check==0)
47 {
48 flag=false;
49 return ;
50 }
51 if(check+d>deep) return ;
52 int row,col,cantorValue;
53 for(int i=0;i<4;i++){
54 row=startPoint.position/3+dir[i][0];
55 col=startPoint.position%3+dir[i][1];
56 if(row<0||col<0||row>=3||col>=3) continue;
57 Point p(startPoint),assistPoint(startPoint);
58 p.eightMap[p.position]=p.eightMap[col+row*3];
59 p.position=col+row*3;
60 p.eightMap[p.position]='x';
61 cantorValue=cantor(p);
62 if(visited[cantorValue]) continue;
63 visited[cantorValue]=true;
64 op[d]=option[i];
65 startPoint=p;
66 dfs(d+1);
67 if(!flag) return ;
68 startPoint=assistPoint;
69 visited[cantorValue]=false;
70 }
71 return ;
72 }
73
74 inline bool inversionNumberCheck(){
75 int cnt=0;
76 for(int i=0;i<N;i++){
77 if(startPoint.eightMap[i]=='x') continue;
78 for(int k=i-1;k>=0;k--){
79 if(startPoint.eightMap[k]=='x') continue;
80 if(startPoint.eightMap[k]>startPoint.eightMap[i])
81 cnt++;
82 }
83 }
84 return cnt&1;
85 }
86 int main(){
87 //fstream cin("Eight.txt");
88 while(cin>>startPoint.eightMap[0])
89 {
90 if(startPoint.eightMap[0]=='x')
91 startPoint.position=0;
92 for(int i=1;i<9;i++)
93 {
94 cin>>startPoint.eightMap[i];
95 if(startPoint.eightMap[i]=='x')
96 startPoint.position=i;
97 }
98 if(inversionNumberCheck()){
99 cout<<"unsolvable"<<endl;
100 continue;
101 }
102 deep=h(startPoint);
103 memset(visited,false,sizeof(visited));
104 memset(op,false,sizeof(op));
105 flag=true;
106 while(flag)
107 {
108 deep++;
109 dfs(0);
110 }
111 for (int i=0;op[i]!=NULL;i++)//不能以deep作为终点否则,如果op清空,则会产生空格;如果op为清空,则输出错误的字符
112 cout<<op[i];
113 cout<<endl;
114 }
115 }



posted on 2011-09-21 15:10  AdaByron  阅读(838)  评论(0)    收藏  举报

导航