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

 

 

 

 

转载于:https://www.cnblogs.com/LyonLys/archive/2012/12/18/poj_1077_Lyon.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值