zoukankan      html  css  js  c++  java
  • 【转】别人家的八数码 A* IDA*解法

    【转】 http://www.cnblogs.com/liyongmou/archive/2010/07/19/1780861.html

      1 代码
      2 
      3 // A*
      4 #include<iostream>
      5 #include<cstdio>
      6 #include<cstring>
      7 #include<cstdlib>
      8 #include<queue>
      9 using namespace std;
     10 
     11 /* 把1..n的排列映射为数字 0..(n!-1) */
     12 int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };//...
     13 int order(const char *s, int n) {
     14     int i, j, temp, num;
     15 
     16     num = 0;
     17 
     18     for (i = 0; i < n-1; i++) {
     19         temp = 0;
     20         for (j = i + 1; j < n; j++) {
     21             if (s[j] < s[i])
     22                 temp++;
     23         }
     24         num += fac[s[i] -1] * temp;
     25     }
     26     return num;
     27 }
     28 
     29 bool is_equal(const char *b1, const char *b2){
     30     for(int i=0; i<9; i++)
     31         if(b1[i] != b2[i])
     32             return false;
     33     return true;
     34 }
     35 
     36 
     37 //hash
     38 struct node{
     39     char board[9];
     40     char space;//空格所在位置
     41 };
     42 
     43 const int TABLE_SIZE = 362880;
     44 
     45 int hash(const char *cur){
     46     return order(cur, 9);
     47 }
     48 
     49 /* 整数映射成排列 */
     50 void get_node(int num, node &tmp) {
     51     int n=9;
     52     int a[9]; //求逆序数
     53     for (int i = 2; i <= n; ++i) {
     54         a[i - 1] = num % i;
     55         num = num / i;
     56         tmp.board[i - 1] = 0;//初始化
     57     }
     58     tmp.board[0] = 0;
     59     int rn, i;
     60     for (int k = n; k >= 2; k--) {
     61         rn = 0;
     62         for (i = n - 1; i >= 0; --i) {
     63             if (tmp.board[i] != 0)
     64                 continue;
     65             if (rn == a[k - 1])
     66                 break;
     67             ++rn;
     68         }
     69         tmp.board[i] = k;
     70     }
     71     for (i = 0; i < n; ++i)
     72         if (tmp.board[i] == 0) {
     73             tmp.board[i] = 1;
     74             break;
     75         }
     76     tmp.space = n - a[n-1] -1;
     77 }
     78 
     79 //启发函数: 除去x之外到目标的网格距离和
     80 int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
     81         {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
     82 int h(const char *board){
     83     int k;
     84     int hv = 0;
     85     for(int i=0; i<3; ++i)
     86         for(int j=0; j<3; ++j){
     87             k = i*3+j;
     88             if(board[k] != 9){
     89                 hv += abs(i - goal_state[board[k]-1][0]) +
     90                         abs(j - goal_state[board[k] -1][1]);
     91             }
     92         }
     93     return hv;
     94 }
     95 
     96 int f[TABLE_SIZE], d[TABLE_SIZE];//估计函数和深度
     97 
     98 //优先队列的比较对象
     99 struct cmp{
    100     bool operator () (int u, int v){
    101         return f[u] > f[v];
    102     }
    103 };
    104 char color[TABLE_SIZE];//0, 未访问;1, 在队列中,2, closed
    105 int parent[TABLE_SIZE];
    106 char move[TABLE_SIZE];
    107 int step[4][2] = {{-1, 0},{1, 0}, {0, -1}, {0, 1}};//u, d, l, r
    108 
    109 void A_star(const node & start){
    110     int x, y, k, a, b;
    111     int u, v;
    112     priority_queue<int, vector<int>, cmp> open;
    113     memset(color, 0, sizeof(char) * TABLE_SIZE);
    114 
    115     u = hash(start.board);
    116     parent[u] = -1;
    117     d[u] = 0;
    118     f[u] = h(start.board);
    119     open.push(u);
    120     color[u] = 1;
    121 
    122     node tmp, cur;
    123     while(!open.empty()){
    124         u = open.top();
    125         if(u == 0)
    126             return;
    127         open.pop();
    128 
    129         get_node(u, cur);
    130 
    131         k = cur.space;
    132         x = k / 3;
    133         y = k % 3;
    134         for(int i=0; i<4; ++i){
    135             a = x + step[i][0];
    136             b = y + step[i][1];
    137             if(0<=a && a<=2 && 0<=b && b<=2){
    138                 tmp = cur;
    139                 tmp.space = a*3 + b;
    140                 swap(tmp.board[k], tmp.board[tmp.space]);
    141                 v = hash(tmp.board);
    142                 if(color[v] == 1 && (d[u] + 1) < d[v]){//v in open
    143                     move[v] = i;
    144                     f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
    145                     d[v] = d[u] + 1;
    146                     parent[v] = u;
    147                     //直接插入新值, 有冗余,但不会错
    148                     open.push(v);
    149                 }
    150                 else if(color[v] == 2 && (d[u]+1)<d[v]){//v in closed
    151                     move[v] = i;
    152                     f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
    153                     d[v] = d[u] + 1;
    154                     parent[v] = u;
    155                     open.push(v);
    156                     color[v] = 1;
    157                 }
    158                 else if(color[v] == 0){
    159                     move[v] = i;
    160                     d[v] = d[u] + 1;
    161                     f[v] = d[v] + h(tmp.board);
    162                     parent[v] = u;
    163                     open.push(v);
    164                     color[v] = 1;
    165                 }
    166             }
    167         }
    168         color[u] = 2; //
    169     }
    170 }
    171 
    172 void print_path(){
    173     int n, u;
    174     char path[1000];
    175     n = 1;
    176     path[0] = move[0];
    177     u = parent[0];
    178     while(parent[u] != -1){
    179         path[n] = move[u];
    180         ++n;
    181         u = parent[u];
    182     }
    183     for(int i=n-1; i>=0; --i){
    184         if(path[i] == 0)
    185             printf("u");
    186         else if(path[i] == 1)
    187             printf("d");
    188         else if(path[i] == 2)
    189             printf("l");
    190         else
    191             printf("r");
    192     }
    193 }
    194 
    195 int main(){
    196     //freopen("in", "r", stdin);
    197 
    198     node start;
    199     char c;
    200     for(int i=0; i<9; ++i){
    201         cin>>c;
    202         if(c == 'x'){
    203             start.board[i] = 9;
    204             start.space = i;
    205         }
    206         else
    207             start.board[i] = c - '0';
    208     }
    209     A_star(start);
    210 
    211     if(color[0] != 0)
    212         print_path();
    213     else
    214         printf("unsolvable");
    215     return 0;
    216 }
    A*
     1 代码
     2 
     3 // IDA*
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<cstdlib>
     7 using namespace std;
     8 
     9 #define    SIZE 3
    10 
    11 char board[SIZE][SIZE];
    12 
    13 //启发函数: 除去x之外到目标的网格距离和
    14 int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
    15         {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
    16 int h(char board[][SIZE]){
    17     int cost = 0;
    18     for(int i=0; i<SIZE; ++i)
    19         for(int j=0; j<SIZE; ++j){
    20             if(board[i][j] != SIZE*SIZE){
    21                 cost += abs(i - goal_state[board[i][j]-1][0]) +
    22                         abs(j - goal_state[board[i][j]-1][1]);
    23             }
    24         }
    25     return cost;
    26 }
    27 
    28 int step[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};//u, l, r, d
    29 char op[4] = {'u', 'l', 'r', 'd'};
    30 
    31 char solution[1000];
    32 int bound;     //上界
    33 bool ans;    //是否找到答案
    34 int DFS(int x, int y, int dv, char pre_move){// 返回next_bound
    35     int hv = h(board);
    36     if(hv + dv > bound)
    37         return dv + hv;
    38     if(hv == 0){
    39         ans = true;
    40         return dv;
    41     }
    42 
    43     int next_bound = 1e9;
    44     for(int i=0; i<4; ++i){
    45         if(i + pre_move == 3)//与上一步相反的移动
    46             continue;
    47         int nx = x + step[i][0];
    48         int ny = y + step[i][1];
    49         if(0<=nx && nx<SIZE && 0<=ny && ny<SIZE){
    50             solution[dv] = i;
    51             swap(board[x][y], board[nx][ny]);
    52 
    53             int new_bound = DFS(nx, ny, dv+1, i);
    54             if(ans)
    55                 return new_bound;
    56             next_bound = min(next_bound, new_bound);
    57 
    58             swap(board[x][y], board[nx][ny]);
    59         }
    60     }
    61     return next_bound;
    62 }
    63 
    64 void IDA_star(int sx, int sy){
    65     ans = false;
    66     bound = h(board);//初始代价
    67     while(!ans && bound <= 100)//上限
    68         bound = DFS(sx, sy, 0, -10);
    69 }
    70 
    71 int main(){
    72     freopen("in", "r", stdin);
    73 
    74     int sx, sy;//起始位置
    75     char c;
    76     for(int i=0; i<SIZE; ++i)
    77         for(int j=0; j<SIZE; ++j){
    78             cin>>c;
    79             if(c == 'x'){
    80                 board[i][j] = SIZE * SIZE;
    81                 sx = i;
    82                 sy = j;
    83             }
    84             else
    85                 board[i][j] = c - '0';
    86         }
    87 
    88     IDA_star(sx, sy);
    89 
    90     if(ans){
    91         for(int i=0; i<bound; ++i)
    92             cout<<op[solution[i]];
    93     }
    94     else
    95         cout<<"unsolvable";
    96 
    97     return 0;
    98 }
    IDA*
  • 相关阅读:
    eclipse安装WTP部署WEB项目
    BZOJ3302: [Shoi2005]树的双中心
    BZOJ2059: [Usaco2010 Nov]Buying Feed 购买饲料
    BZOJ1986: [USACO2004 Dec] Dividing the Path 划区灌溉
    BZOJ3126: [Usaco2013 Open]Photo
    51nod1486 大大走格子
    BZOJ1698: [Usaco2007 Feb]Lilypad Pond 荷叶池塘
    BZOJ2590: [Usaco2012 Feb]Cow Coupons
    BZOJ1739: [Usaco2005 mar]Space Elevator 太空电梯
    BZOJ2501: [usaco2010 Oct]Soda Machine
  • 原文地址:https://www.cnblogs.com/wsaaaaa/p/4499961.html
Copyright © 2011-2022 走看看