POJ 1077 HDU 1043 Eight (IDA*)

来源:互联网 发布:银行卡照片制作软件 编辑:程序博客网 时间:2024/06/05 05:29

题意就不用再说明了吧......如此经典

之前想用双向广搜、a*来写,但总觉得无力,现在用IDA*感觉其他的解法都弱爆了..............想法活跃,时间,空间消耗很小,给它跪了


启发式搜索关键还是找估价函数:此题估价函数可大致定性为每个数字(除去x,只要8个数字)当前位置与它期望位置的曼哈顿距离

即为:v += abs(i - pos[map[i][j] - 1][0]);     v += abs(j - pos[map[i][j] - 1][1]);     大致估算为几十步内得出结果。

#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#include <climits>//形如INT_MAX一类的#define MAX 100005#define INF 0x7FFFFFFF#define REP(i,s,t) for(int i=(s);i<=(t);++i)#define ll long long#define mem(a,b) memset(a,b,sizeof(a))#define mp(a,b) make_pair(a,b)#define L(x) x<<1#define R(x) x<<1|1# define eps 1e-5//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂using namespace std;int pos[9][2] = {  //各个数字的初始位置    {0,0},{0,1},{0,2},    {1,0},{1,1},{1,2},    {2,0},{2,1},{2,2}};int map[4][4];int buff[50];char input[11];int limit,ok;int dx[] = {-1,0,1,0}; //u r d l____0 1 2 3int dy[] = {0,1,0,-1};char op[] = {'u','r','d','l'};int h(int x,int y) {    int v = 0;    for(int i=0; i<3; i++) {        for(int j=0; j<3; j++) {            if(i != x || j != y) {                v += abs(i - pos[map[i][j] - 1][0]);                v += abs(j - pos[map[i][j] - 1][1]);            }        }    }    return v;}int dfs(int x,int y,int step,int pre) {    int hn = h(x,y);    if(hn == 0) {        ok = 1;        return step;    }    if(hn + step > limit) return hn + step;    int minn = INF;    for(int i=0; i<4; i++) {        if(abs(i - pre) == 2) continue;        int xx = x + dx[i];        int yy = y + dy[i];        if(xx<0 || xx >=3 || yy<0 || yy >=3) continue;        buff[step] = i;        swap(map[x][y],map[xx][yy]);        int tmp = dfs(xx,yy,step+1,i);        if(ok) return tmp;        minn = min(tmp,minn);        swap(map[x][y],map[xx][yy]);    }    return minn;}void IDA_star(int x,int y) {    ok = 0;    memset(buff,-1,sizeof(buff));    while(ok == 0 && limit <= 36) {        limit = dfs(x,y,0,-111);    }    if(ok == 1) {        for(int i=0; i<limit; i++) printf("%c",op[buff[i]]);        puts("");    } else puts("unsolvable");}int main() {    for(int i=0; i<9; i++) cin >> input[i];    int t = 0,x,y;    for(int i=0; i<3; i++) {        for(int j=0; j<3; j++) {            if(input[t] == 'x') {                map[i][j] = 9;                x = i;                y = j;                t++;            } else map[i][j] = input[t++] - '0';        }    }    int limit = h(x,y);    if(limit == 0) {        puts("");        return 0;    }    IDA_star(x,y);    return 0;}

想吐槽一下杭电的这题.........估计各种无法到达目标的数据,所以在输入时候通过求逆序数对数来判断是否有解,本来是TLE,一下蹦到171ms

#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#include <climits>//形如INT_MAX一类的#define MAX 100005#define INF 0x7FFFFFFF#define REP(i,s,t) for(int i=(s);i<=(t);++i)#define ll long long#define mem(a,b) memset(a,b,sizeof(a))#define mp(a,b) make_pair(a,b)#define L(x) x<<1#define R(x) x<<1|1# define eps 1e-5//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂using namespace std;int pos[9][2] = {  //各个数字的初始位置    {0,0},{0,1},{0,2},    {1,0},{1,1},{1,2},    {2,0},{2,1},{2,2}};int map[4][4];int buff[50];char input[11];int limit,ok;int dx[] = {-1,0,1,0}; //u r d l____0 1 2 3int dy[] = {0,1,0,-1};char op[] = {'u','r','d','l'};int h(int x,int y) {    int v = 0;    for(int i=0; i<3; i++) {        for(int j=0; j<3; j++) {            if(i != x || j != y) {                v += abs(i - pos[map[i][j] - 1][0]);                v += abs(j - pos[map[i][j] - 1][1]);            }        }    }    return v;}int dfs(int x,int y,int step,int pre) {    int hn = h(x,y);    if(hn == 0) {        ok = 1;        return step;    }    if(hn + step > limit) return hn + step;    int minn = INF;    for(int i=0; i<4; i++) {        if(abs(i - pre) == 2) continue;        int xx = x + dx[i];        int yy = y + dy[i];        if(xx<0 || xx >=3 || yy<0 || yy >=3) continue;        buff[step] = i;        swap(map[x][y],map[xx][yy]);        int tmp = dfs(xx,yy,step+1,i);        if(ok) return tmp;        minn = min(tmp,minn);        swap(map[x][y],map[xx][yy]);    }    return minn;}int canget(int a[4][4]) { //这一步省了好多时间 求逆序数对数    int i,j,sum=0,b[10],k=0;    for(i=0; i<3; i++) {        for(j=0; j<3; j++) {            if(a[i][j] != 9)                b[++k]=a[i][j];        }    }    for(i=1; i<=8; i++) {        for(j=1; j<i; j++) {            if(b[i]<b[j])sum++;        }    }    if(sum % 2 ==0)return 1;    else return 0;}void IDA_star(int x,int y) {    ok = 0;    memset(buff,-1,sizeof(buff));    while(ok == 0 && limit <= 30) {        limit = dfs(x,y,0,-111);    }    if(ok == 1) {        for(int i=0; i<limit; i++) printf("%c",op[buff[i]]);        puts("");    } else puts("unsolvable");}int main() {    while(cin >> input[0]) {        //memset(map,0,sizeof(map));        for(int i=1; i<9; i++) cin >> input[i];        int t = 0,x,y;        for(int i=0; i<3; i++) {            for(int j=0; j<3; j++) {                if(input[t] == 'x') {                    map[i][j] = 9;                    x = i;                    y = j;                    t++;                } else map[i][j] = input[t++] - '0';            }        }        limit = h(x,y);        if(limit == 0) {            puts("");            continue;        }        if(canget(map))            IDA_star(x,y);        else puts("unsolvable");    }    return 0;}


经过猥琐的测试,limit最小限制在29步....................