当前位置: 代码迷 >> 综合 >> POJ 2286 UVA 1343 The Rotation Game IDA*
  详细解决方案

POJ 2286 UVA 1343 The Rotation Game IDA*

热度:57   发布时间:2023-09-23 07:28:31.0

以前看刘汝佳的方法写过,现在再写一遍

以下是自己意淫的IDA*

g()是旋转的次数 ;

h()的求法:每次移动最多只会使得中央区域包含的数字种类减少1种。求出中央区域个数最多的那个数字的个数 n, 要达到中央区域数字都相同,至少需要 8-n次操作,此即估价函数值

//         1     2
//         3     4
//   5  6  7  8  9  10 11
//         12    13
//   14 15 16 17 18 19 20  
//         21    22
//         23    24
#include<cstdio>
#include<cstring>
#include<queue> 
#include<set> 
#include<string> 
#include<algorithm>
#include<iostream>
#define min3(x,y,z) min(x,min(y,z))
using namespace std;
const int center[]={7,8,9,12,13,16,17,18};
const int Move[8][7]={{1,3,7,12,16,21,23},{2,4,9,13,18,22,24},{11,10,9,8,7,6,5},{20,19,18,17,16,15,14},{24,22,18,13,9,4,2},{23,21,16,12,7,3,1},{14,15,16,17,18,19,20},{5,6,7,8,9,10,11}
};
const char d[]="ABCDEFGH";
int Board[25];
int diff(int *B,int n){int cnt=0;for(int i=0;i<8;i++)if(B[center[i]]!=n) cnt++;return cnt;
}
int H(int *B){return min3(diff(B,1),diff(B,2),diff(B,3));
}
struct Node{int Board[25]; string path; int f,g,h;Node(int *b,int g,string p):g(g),path(p){memcpy(Board,b,sizeof(Board));h=H(b);f=g+h;}bool operator < (const Node& n) const{if(f==n.f) return path>n.path;  //保证字典序 return f>n.f;}
};
set<long long> closed;
bool inClosed(int* B){long long code=0;for(int i=1;i<=24;i++){code|=B[i];code<<=2;}if(closed.count(code)) return true;closed.insert(code);return false;
}
bool A_Star(int maxd)
{priority_queue<Node> open; closed.clear();open.push(Node(Board,0,""));int nBoard[25];while(!open.empty()){Node u=open.top(); open.pop();if(u.h==0){cout<<(u.g?u.path:"No moves needed")<<endl<<u.Board[7]<<endl;return true;}if(u.g+u.h>maxd) continue;for(int i=0;i<8;i++){memcpy(nBoard,u.Board,sizeof(nBoard));for(int j=0;j<6;j++)   nBoard[Move[i][j]]=u.Board[Move[i][j+1]];nBoard[Move[i][6]]=u.Board[Move[i][0]];if(inClosed(nBoard)) continue;open.push(Node(nBoard,u.g+1,u.path+d[i]));}}return false; 
}
int main()
{while(scanf("%d",&Board[1])&&Board[1]){for(int i=2;i<=24;i++) scanf("%d",&Board[i]);for(int i=1;i<=24;i++) if(!Board[i]) break;for(int maxd=1;;maxd++)if(A_Star(maxd)) break;}return 0;
}


结果WR 因为答案求出来并非字典序最小,我的策略是优先比较f(),如果f()相同就比较字典序,而有可能f()大的反而字典序小,因为h()中并未体现字典序,所以单单比较f并非字典序最小,

输入 1 2 2 3 3 3 1 1 1 1 2 2 2 2 3 3 3 3 3 1 1 1 1 1 正确的是:GBBCGAAA ,而我的是GBBGCAAA

所以只能比较g,且在g相同的时候path最小,类似BFS

比较函数改成如下就AC了

struct Node{int Board[25]; string path; int f,g,h;Node(int *b,int g,string p):g(g),path(p){memcpy(Board,b,sizeof(Board));h=H(b);f=g+h;}bool operator < (const Node& n) const{if(g==n.g) return path>n.path;return g>n.g;}
};


但超级慢,2000MS+

所以不如用DFS,首先是天然的字典序,其次无需浪费判重的时间,而且深搜索一开始不会像BFS重复


BFS如下:160MS

//         1     2
//         3     4
//   5  6  7  8  9  10 11
//         12    13
//   14 15 16 17 18 19 20  
//         21    22
//         23    24
#include<cstdio>
#include<cstring>
#include<queue> 
#include<set> 
#include<string> 
#include<algorithm>
#include<iostream>
#define min3(x,y,z) min(x,min(y,z))
using namespace std;
const int center[]={7,8,9,12,13,16,17,18};
const int rev[]={5,4,7,6,1,0,3,2};
const int Move[8][7]={{1,3,7,12,16,21,23},{2,4,9,13,18,22,24},{11,10,9,8,7,6,5},{20,19,18,17,16,15,14},{24,22,18,13,9,4,2},{23,21,16,12,7,3,1},{14,15,16,17,18,19,20},{5,6,7,8,9,10,11}
};
int Board[25];
int diff(int n){int cnt=0;for(int i=0;i<8;i++)if(Board[center[i]]!=n) cnt++;return cnt;
}
int H(){return min3(diff(1),diff(2),diff(3));
}
int solved(){for(int i=1;i<8;i++)if(Board[center[0]]!=Board[center[i]]) return false;return true;
}
void move(int i){int tmp=Board[Move[i][0]];for(int j=0;j<6;j++)   Board[Move[i][j]]=Board[Move[i][j+1]];Board[Move[i][6]]=tmp;
}
char ans[1000];
bool DFS(int dep,int maxd)
{if(solved()) {ans[dep]='\0';return true;}if(dep+H()>maxd) return false;for(int i=0;i<8;i++){ans[dep]='A'+i;move(i);if(DFS(dep+1,maxd)) return true;move(rev[i]);}return false;
}
int main()
{while(scanf("%d",&Board[1])&&Board[1]){for(int i=2;i<=24;i++) scanf("%d",&Board[i]);if(solved()) cout<<"No moves needed"<<endl;else{for(int maxd=1;;maxd++)if(DFS(0,maxd)) break;cout<<ans<<endl;}cout<<Board[7]<<endl;}return 0;
}






  相关解决方案