• poj 1077 Eight (bfs+康拓展开,A*&&IDA*算法)


    http://poj.org/problem?id=1077

      一道经典到不能再经典的搜做题,留到了今天,终于过了,好开心!!!

      这题可以用很多中方法来做,例如bfs,dfs,A*,IDA*什么的。下面是我用普通bfs加上康拓展开来做的代码,800+ms险过的。

    View Code
      1 bool used[N];
      2 char elem[10] = "12345678x";
      3 const char *end = "12345678x";
      4 
      5 int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
      6 template <class T>
      7 int getPos(T *arr, int len) {
      8     int ret, cnt;
      9     VBL vis(len, false);
     10     ret = 1;
     11     REP(i, len) {
     12         cnt = 0;
     13         FORI(j, i + 1, len) {
     14             if (*(arr + i) > *(arr + j)) cnt++;
     15         }
     16         ret += cnt * fac[len - i - 1];
     17     }
     18     return ret;
     19 }
     20 template <class T>
     21 bool getArray(T *arr, int len, int k) {
     22     if (k < 1 || k > fac[len]) return false;
     23     int pos = 0, num, cnt;
     24     T *tmp = new T[len];
     25     VBL vis(len, false);
     26     REP_1(i, len - 1) {
     27         num = (k - 1) / fac[len - i] + 1, cnt = 0;
     28         REP(j, len) {
     29             if (!vis[j]) cnt++;
     30             if (cnt == num) {
     31                 tmp[pos++] = arr[j];
     32                 vis[j] = true;
     33                 break;
     34             }
     35         }
     36         k -= (num - 1) * fac[len - i];
     37     }
     38     REP(i, len) {
     39         if (!vis[i]) tmp[pos++] = arr[i];
     40     }
     41     REP(i, len) arr[i] = tmp[i];
     42     return true;
     43 }
     44 
     45 
     46 char st[10];
     47 bool input() {
     48     char *p = st;
     49     char buf[3];
     50     REP(i, 9) {
     51         if (!(cin >> buf)) return false;
     52         *(p++) = *buf;
     53     }
     54 //    cout << st << endl;
     55     *p = 0;
     56     return true;
     57 }
     58 
     59 char q[N][10], op[N], ans[N];
     60 int qh, qt;
     61 int last[N];
     62 
     63 void find(char *s, int &x, int &y) {
     64     REP(i, 9) if (*(s + i) == 'x') {
     65         x = i % 3, y = i / 3;
     66         break;
     67     }
     68 }
     69 
     70 int bfs() {
     71     qh = qt = 0;
     72     _clr(used);
     73     strcpy(q[qt++], st);
     74     int mk, x, y, cnt = 0, idx;
     75     while (qh < qt) {
     76         mk = qt;
     77         while (qh < mk) {
     78 //            cout << q[qh] << endl;
     79 //            cout << qh << endl;
     80             if (!strcmp(q[qh], end)) return cnt;
     81             find(q[qh], x, y);
     82             if (0 <= x - 1 && x - 1 < 3) {
     83                 swap(q[qh][y * 3 + x], q[qh][y * 3 + x - 1]);
     84                 idx = getPos(q[qh], 9);
     85                 if (!used[idx]) {
     86                     used[idx] = true;
     87                     strcpy(q[qt], q[qh]);
     88                     last[qt] = qh;
     89                     op[qt++] = 'l';
     90                 }
     91                 swap(q[qh][y * 3 + x], q[qh][y * 3 + x - 1]);
     92             }
     93             if (0 <= x + 1 && x + 1 < 3) {
     94                 swap(q[qh][y * 3 + x], q[qh][y * 3 + x + 1]);
     95                 idx = getPos(q[qh], 9);
     96                 if (!used[idx]) {
     97                     used[idx] = true;
     98                     strcpy(q[qt], q[qh]);
     99                     last[qt] = qh;
    100                     op[qt++] = 'r';
    101                 }
    102                 swap(q[qh][y * 3 + x], q[qh][y * 3 + x + 1]);
    103             }
    104             if (0 <= y - 1 && y - 1 < 3) {
    105                 swap(q[qh][y * 3 + x], q[qh][(y - 1) * 3 + x]);
    106                 idx = getPos(q[qh], 9);
    107                 if (!used[idx]) {
    108                     used[idx] = true;
    109                     strcpy(q[qt], q[qh]);
    110                     last[qt] = qh;
    111                     op[qt++] = 'u';
    112                 }
    113                 swap(q[qh][y * 3 + x], q[qh][(y - 1) * 3 + x]);
    114             }
    115             if (0 <= y + 1 && y + 1 < 3) {
    116                 swap(q[qh][y * 3 + x], q[qh][(y + 1) * 3 + x]);
    117                 idx = getPos(q[qh], 9);
    118                 if (!used[idx]) {
    119                     used[idx] = true;
    120                     strcpy(q[qt], q[qh]);
    121                     last[qt] = qh;
    122                     op[qt++] = 'd';
    123                 }
    124                 swap(q[qh][y * 3 + x], q[qh][(y + 1) * 3 + x]);
    125             }
    126             qh++;
    127         }
    128         cnt++;
    129     }
    130     return -1;
    131 }
    132 
    133 void print(int l) {
    134     int rec = qh;
    135     ans[l] = 0;
    136     while (l--) {
    137         ans[l] = op[rec];
    138         rec = last[rec];
    139     }
    140     cout << ans << endl;
    141 }
    142 
    143 int main() {
    144 //    freopen("in", "r",stdin);
    145     while (input()) {
    146         int len = bfs();
    147 //        cout << len << endl;
    148         if (~len) print(len);
    149         else puts("unsolvable");
    150     }
    151     return 0;
    152 }

      A*,IDA*等方法之后将补充上去。

    UPD:对于HDU 1043,预处理BFS的所有情况,250ms通过:(这种方法用于POJ 1077会超时)

    View Code
      1 int fac[15];
      2 void preFac() {
      3     fac[0] = 1;
      4     REP_1(i, 10) fac[i] = fac[i - 1] * i;
      5 }
      6 
      7 template <class T>
      8 int getPos(T *arr, int len) {
      9     int ret = 1, cnt;
     10     VBL vis(len, false);
     11     REP(i, len) {
     12         cnt = 0;
     13         INC(j, i + 1, len) if (*(arr + i) > *(arr + j)) cnt++;
     14         ret += cnt * fac[len - i - 1];
     15     }
     16     return ret;
     17 }
     18 
     19 bool used[N];
     20 int fth[N], qh, qt;
     21 char st[10], dr[N], Q[N][10];
     22 
     23 bool valid(int x, int y) {
     24     if (0 <= x && x <= 2 && 0 <= y && y <= 2) return true;
     25     return false;
     26 }
     27 
     28 const int dir[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
     29 const char dirch[4] = {'d', 'u', 'r', 'l'};
     30 
     31 void fxy(char *str, int &x, int &y) {
     32     int i = 0;
     33     while (*(str++) != 'x') i++;
     34     x = i % 3;
     35     y = i / 3;
     36 }
     37 
     38 void preBFS() {
     39     preFac();
     40     qh = qt = 0;
     41     int x, y, num;
     42     int nx, ny;
     43     REP(i, 8) {
     44         st[i] = i + '1';
     45     }
     46     st[8] = 'x';
     47     strcpy(Q[qt++], st);
     48     used[getPos(st, 9)] = true;
     49     while (qh < qt) {
     50         strcpy(st, Q[qh++]);
     51 //        puts(st);
     52         fxy(st, x, y);
     53 //        cout << x << ends << y << endl;
     54         int tmp  = getPos(st, 9);
     55         REP(i, 4) {
     56             nx = x + dir[i][0];
     57             ny = y + dir[i][1];
     58             if (!valid(nx, ny)) continue;
     59             swap(st[y * 3 + x], st[ny * 3 + nx]);
     60             num = getPos(st, 9);
     61 //            puts(st);
     62 //            cout << num << "??" << endl;
     63             if (!used[num]) {
     64                 strcpy(Q[qt++], st);
     65                 used[num] = true;
     66                 fth[num] = tmp;
     67                 dr[num] = dirch[i];
     68             }
     69             swap(st[y * 3 + x], st[ny * 3 + nx]);
     70         }
     71     }
     72 }
     73 
     74 bool input() {
     75     char buf[3];
     76     REP(i, 9) {
     77         if (scanf("%s", buf) == -1) return false;
     78         st[i] = buf[0];
     79     }
     80     return true;
     81 }
     82 
     83 void print() {
     84     int cur = getPos(st, 9);
     85 //    cout << cur << endl;
     86     if (!used[cur]) {
     87         printf("unsolvable");
     88         return ;
     89     }
     90     while (fth[cur]) {
     91         putchar(dr[cur]);
     92         cur = fth[cur];
     93     }
     94 }
     95 
     96 int main() {
     97     preBFS();
     98     while (input()) {
     99         print();
    100         puts("");
    101     }
    102     return 0;
    103 }

    UPD:

    A*算法:

    http://www.java3z.com/cwbwebhome/article/article2/2825.html

      这是我认为解释A*算法解释的最生动的一个网页之一,通过这个网站上的flash演示,可以更容易理解A*算法。

    下面是用A*算法的通过代码,搞这个代码debug用了我挺长的时间的,原因是不小心将方向还有输出顺序搞混了。HDU上跑,接近3000ms,POJ上跑,大约110ms。

    View Code
      1 int fac[15];
      2 void preFac() {
      3     fac[0] = 1;
      4     REP_1(i, 10) fac[i] = fac[i - 1] * i;
      5 }
      6 
      7 template <class T>
      8 int getPos(T *arr, int len) {
      9     int ret = 1, cnt;
     10     REP(i, len) {
     11         cnt = 0;
     12         INC(j, i + 1, len) if (*(arr + i) > *(arr + j)) cnt++;
     13         ret += cnt * fac[len - i - 1];
     14     }
     15     return ret;
     16 }
     17 
     18 bool valid(int x, int y) {
     19     if (0 <= x && x <= 2 && 0 <= y && y <= 2) return true;
     20     return false;
     21 }
     22 
     23 const int dir[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
     24 const char dirch[4] = {'u', 'd', 'l', 'r'};
     25 
     26 void fxy(char *str, int &x) {
     27     int i = 0;
     28     while (*(str++) != '9') i++;
     29     x = i;
     30 }
     31 
     32 int next[9][4];
     33 
     34 void preNext() {
     35     REP(i, 9) {
     36         REP(j, 4) {
     37             if (valid(i % 3 + dir[j][0], i / 3 + dir[j][1])) {
     38                 next[i][j] = i + dir[j][0] + dir[j][1] * 3;
     39             } else next[i][j] = -1;
     40         }
     41     }
     42 }
     43 
     44 bool input(char *st) {
     45     char buf[3];
     46     REP(i, 9) {
     47         if (scanf("%s", buf) == -1) return false;
     48         st[i] = buf[0];
     49         if (st[i] == 'x') st[i] = '9';
     50     }
     51     return true;
     52 }
     53 
     54 bool vis[N];
     55 int f[N];
     56 char recDir[N];
     57 int pos[9][2], minStep[N];
     58 
     59 void prePos() {
     60     REP(i, 9) {
     61         pos[i][0] = i % 3;
     62         pos[i][1] = i / 3;
     63     }
     64 }
     65 
     66 int h(char *st) {
     67     int ret = 0;
     68     REP(i, 9) {
     69         if (*st != '9') ret += abs(i % 3 - pos[*st - '1'][0]) + abs(i / 3 - pos[*st - '1'][1]);
     70         st++;
     71     }
     72     return ret;
     73 }
     74 
     75 bool isSovlable(char *st) {
     76     int t;
     77     fxy(st, t);
     78     t = t % 3 + t / 3;
     79     REP(i, 9) {
     80         REP(j, i) {
     81             if (st[i] > st[j]) t++;
     82         }
     83     }
     84 //    cout << t << endl;
     85     return (t & 1) == 0;
     86 }
     87 
     88 bool AStar(char *st) {
     89     if (!isSovlable(st)) return false;
     90     PIIS tmp;
     91     PRIQ<PIIS, vector<PIIS>, greater<PIIS> > PQ;
     92     int idx = getPos(st, 9), x;
     93     char stTmp[10];
     94 
     95     _clr(f);
     96     _clr(recDir);
     97     _clr(vis);
     98     _clr(minStep);
     99     while (!PQ.empty()) PQ.pop();
    100     vis[idx] = true;
    101     PQ.push(MPR(MPR(0 + h(st), 0), st));
    102 
    103     while (!PQ.empty()) {
    104         tmp = PQ.top();
    105         PQ.pop();
    106         strcpy(stTmp, tmp.SE.c_str());
    107 //        cout << stTmp << endl;
    108 //        cout << tmp.FI.FI << endl;
    109         int cur = getPos(stTmp, 9);
    110         if (cur == 1) return true;
    111         fxy(stTmp, x);
    112         REP(i, 4) {
    113             if (next[x][i] == -1) continue;
    114             swap(stTmp[x], stTmp[next[x][i]]);
    115             idx = getPos(stTmp, 9);
    116             if (!vis[idx] || minStep[idx] > tmp.FI.SE + 1) {
    117                 vis[idx] = true;
    118                 f[idx] = cur;
    119                 recDir[idx] = dirch[i];
    120                 PQ.push(MPR(MPR(tmp.FI.SE + 1 + h(stTmp), tmp.FI.SE + 1), stTmp));
    121                 minStep[idx] = tmp.FI.SE + 1;
    122             }
    123             swap(stTmp[x], stTmp[next[x][i]]);
    124         }
    125     }
    126     return false;
    127 }
    128 
    129 int main() {
    130 //    freopen("in", "r", stdin);
    131 //    freopen("out", "w", stdout);
    132     char buf[10];
    133     preFac();
    134     prePos();
    135     preNext();
    136     while (input(buf)) {
    137         stack<char> out;
    138         if (AStar(buf)) {
    139             int tmp = 1;
    140             while (f[tmp]) {
    141                 out.push(recDir[tmp]);
    142                 tmp = f[tmp];
    143             }
    144             while (!out.empty()) { putchar(out.top()); out.pop();}
    145             puts("");
    146         } else {
    147             puts("unsolvable");
    148         }
    149     }
    150     return 0;
    151 }
    152 
    153 
    154 /*
    155 1 2 3 4 5 6 x 7 8
    156 1 2 3 x 5 6 4 7 8
    157 */

    UPD:

    IDA*算法:

      加深迭代搜索的A*算法是其实就是一个dfs,只不过和dfs不同的是搜索过程中会限定f(x)=g(x)+h(x)的值。虽然搜索过程中会重复,但是上限剪枝极大的弥补了这个不足,所以跑起来会十分的省时。代码在POJ上跑了16ms,在HDU上是400ms。

    View Code
      1 inline bool inBoard(int x, int y) {
      2     return 0 <= x && x <= 2 && 0 <= y && y <= 2;
      3 }
      4 
      5 int next[9][4];
      6 const int dir[4][2] = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} };
      7 const char dirCH[4] = { 'r', 'u', 'l', 'd' };
      8 
      9 void preNext() {
     10     int nx, ny;
     11     REP(i, 9) {
     12         REP(j, 4) {
     13             nx = i % 3 + dir[j][0];
     14             ny = i / 3 + dir[j][1];
     15             if (inBoard(nx, ny)) next[i][j] = nx + ny * 3;
     16             else next[i][j] = -1;
     17         }
     18     }
     19 }
     20 
     21 const char *endST = "12345678x";
     22 inline bool isFinish(char *str) {
     23     return !strcmp(str, endST);
     24 }
     25 
     26 inline bool canSolve(char *str) {
     27     int cnt = 0;
     28     REP(i, 9) {
     29         if (str[i] == 'x') cnt += i / 3 + i % 3;
     30         REP(j, i) {
     31             if (str[i] < str[j]) cnt++;
     32         }
     33     }
     34     return (cnt & 1) == 0;
     35 }
     36 
     37 inline int h(char *str) {
     38     int ret = 0;
     39     REP(i, 9) {
     40         if (str[i] == 'x') continue;
     41         ret += abs((str[i] - '1') % 3 - i % 3) + abs((str[i] - '1') / 3 - i / 3);
     42     }
     43     return ret;
     44 }
     45 
     46 inline int findPos(char *str) {
     47     REP(i, 9) if (*(str++) == 'x') return i;
     48 }
     49 
     50 bool input(char *str) {
     51     char buf[3];
     52     REP(i, 9) {
     53         if (scanf("%s", buf) == -1) return false;
     54         *(str++) = buf[0];
     55     }
     56     *str = 0;
     57     return true;
     58 }
     59 
     60 char recPath[N];
     61 bool IDAS(int cur, int end, char *str) {
     62     if (isFinish(str)) {
     63         recPath[cur] = '*';
     64         return true;
     65     }
     66     if (cur >= end) return false;
     67     int p = findPos(str);
     68     REP(i, 4) {
     69         if (cur && abs(recPath[cur - 1] - i) == 2) continue;
     70         if (~next[p][i]) {
     71             swap(str[p], str[next[p][i]]);
     72             if (h(str) + cur + 1 <= end) {
     73                 recPath[cur] = i;
     74                 if (IDAS(cur + 1, end, str)) return true;;
     75             }
     76             swap(str[p], str[next[p][i]]);
     77         }
     78     }
     79     return false;
     80 }
     81 
     82 int main() {
     83     char buf[15];
     84     preNext();
     85     while (input(buf)) {
     86         if (!canSolve(buf)) {
     87             puts("unsolvable");
     88             continue;
     89         }
     90         int upBound = h(buf);
     91         while (!IDAS(0, upBound, buf)) {
     92             upBound++;
     93 //            cout << upBound << endl;
     94         }
     95 //        cout << minStep << endl;
     96         char *p = recPath;
     97         while (*p != '*') {
     98             putchar(dirCH[*(p++)]);
     99         }
    100         puts("");
    101     }
    102     return 0;
    103 }

       三种方法相对比,个人认为IDA*相对比较简洁易懂,代码复杂度也是相对低一些的!再加上程序跑的飞起,完胜另外两种方法了。

    ——written by Lyon

  • 相关阅读:
    jQuery.getJSON() – jQuery API
    打造个性化的Select(可编辑)(还不错,有一定实用价值)
    RMAN备份异机恢复并创建新DBID
    输出所有在给定范围内的水仙花数
    使用 ptstalk 诊断 MySQL 问题
    VC6.0 error LNK2001: unresolved external symbol _main解决办法
    Mysql备份
    在从1到n的正数中1出现的次数
    游标sql语句
    linux中如何改IP
  • 原文地址:https://www.cnblogs.com/LyonLys/p/poj_1077_Lyon.html
Copyright © 2020-2023  润新知