【搜索进阶】hdu 1043 Eight

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043
A*: 因为每次移动都会影响一个点的曼哈顿距离(不算x),构造h()为所有数字块的曼哈顿距离和,用逆序数hash(算x),根据逆序数奇偶性(不算x)减掉无法到达的情况;在构造优先队列时当f相同时按照g值从大到小排序,这样又是一个很给力的减枝
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct S {
    char maze[3][3];
    int x , y;
    int g , h , f;
    S() {}
    S(const S& ts) {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                maze[i][j] = ts.maze[i][j];
        x = ts.x; y = ts.y;
        g = ts.g; h = ts.h; f = ts.f;    
    }    
    friend bool operator < (const S& a,const S& b) {
        if(a.f == b.f) return a.g < b.g;
        return a.f > b.f;    
    }
}s;
const int fac[] = {1,1,2,6,24,120,720,5040,40320};
bool vis[363000];
int pre[363000];
char op[363000];
inline int inv_hash(S ts) {
    char str[11]; int ans = 0;
    for(int i=0;i<3;i++) {
        for(int j=0;j<3;j++) {
            str[i*3+j] = ts.maze[i][j];
            int cnt = 0;    
            for(int k=i*3+j-1;k>=0;k--) {
                if(str[k] > str[i*3+j]) cnt++;                
            }
            ans += fac[i*3+j] * cnt;
        }
    }
    return ans;
}
const int pos[][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
inline int abs(int x) { return x < 0 ? -x : x; }
inline int h(S ts) {
    int val = 0;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++) {
            if(ts.maze[i][j] == 'x') continue;
            int c = ts.maze[i][j] - '1';
            val += abs(pos[c][0]-i)+abs(pos[c][1]-j);    
        }    
    return val;
}
const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
bool bfs() {
    memset(vis,false,sizeof(vis));
    priority_queue<S> que;
    que.push(s);
    while(!que.empty()) {
        S u  = que.top(); que.pop();
        int ihu = inv_hash(u);
        for(int i=0;i<4;i++) {
            S v = u;
            v.x += dir[i][0];
            v.y += dir[i][1];
            if(v.x<0||v.y<0||v.x>=3||v.y>=3) continue;
            v.maze[u.x][u.y]=u.maze[v.x][v.y];
            v.maze[v.x][v.y]='x';
            v.g+=1; v.h=h(v); v.f=v.g+v.h;
            int ihv = inv_hash(v);
            if(vis[ihv]) continue;
            vis[ihv] = true;
            pre[ihv] = ihu;
            if(i == 0) op[ihv] = 'd';
            else if(i == 1) op[ihv] = 'r';
            else if(i == 2) op[ihv] = 'u';
            else if(i == 3) op[ihv] = 'l';
            if(ihv == 0) return true;
            que.push(v);    
        }    
    }    
    return false;
}
inline bool inv_check() {
    char str[11];
    int cnt = 0;
    for(int i=0;i<3;i++) {
        for(int j=0;j<3;j++) {
            str[i*3+j] = s.maze[i][j];
            if(str[i*3+j] == 'x') continue;
            for(int k=i*3+j-1;k>=0;k--) {
                if(str[k]=='x') continue;
                if(str[k] > str[i*3+j]) cnt++;    
            }    
        }    
    }    
    return !(cnt&1);
}
char in[111];
char stk[111];
int main() {
    while(gets(in)) {
        for(int i=0,x=0,y=0;in[i];i++) {
            if((in[i]<='9'&&in[i]>='0')||in[i]=='x') {
                s.maze[x][y] = in[i];
                if(in[i]=='x') { s.x=x;s.y=y; }
                y++; if(y == 3) y=0,x++;    
            }
        }    
        if(!inv_check()) { 
            puts("unsolvable");
            continue;
        }
        s.g=0; s.h=h(s); s.f=s.h;
        int shash = inv_hash(s);
        if(shash==0) { puts(""); continue; }
        bfs();
        int top = -1 , thash = 0;
        while(thash != shash) {
            stk[++top] = op[thash];
            thash = pre[thash];    
        }
        for(int i=top;i>=0;i--) {
            putchar(stk[i]);    
        }
        puts("");
    }
    return 0;    
}

单广预处理: 从最终状态向所有状态搜索,记录前驱,然后直接输出就好
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct S{
    char maze[3][3];
    int x,y; 
    S(){}
    S(const char *str){
        for(int i=0,tx=0,ty=0;str[i];i++){
            if((str[i]<='9'&&str[i]>='0')||str[i]=='x'){
                maze[tx][ty]=str[i];
                if(str[i]=='x'){x=tx;y=ty;}
                    ty++;
                    if(ty==3){ty=0;tx++;}
            }
        }
    }
};
int pre[363000];
char op[363000];
const int fac[]={1,1,2,6,24,120,720,5040,40320};
bool  vis[363000];
inline int inv_hash(S ts){
    char str[10]; int ans=0;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            str[i*3+j]=ts.maze[i][j];
            int cnt=0;
            for(int k=i*3+j-1;k>=0;k--){
                if(str[k]>str[i*3+j]) cnt++;
            }
            ans+=fac[i*3+j]*cnt;
        }
    }
    return ans;
} 
S s;
const int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
const char cdir[]="dulr";
void bfs(){
    memset(vis,false,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    queue<S> que;
    que.push(s);
    while(!que.empty()){
        S u=que.front(); que.pop();
        int ihu=inv_hash(u);
        for(int i=0;i<4;i++){
            S v=u;
            v.x+=dir[i][0];
            v.y+=dir[i][1];
            if(v.x<0||v.y<0||v.x>=3||v.y>=3) continue;
            v.maze[u.x][u.y]=v.maze[v.x][v.y];
            v.maze[v.x][v.y]='x';
            int ihv=inv_hash(v);
            if(vis[ihv]) continue;
            vis[ihv]=true;
            pre[ihv]=ihu;
            op[ihv]=cdir[i];
            que.push(v);
        }
    }
} 
char in[100];
char stk[100];
int main(){
    s=S("12345678x");
    bfs();
    while(gets(in)){
        s=S(in);
        int ihs=inv_hash(s);
        if(pre[ihs]==-1){puts("unsolvable");continue;}
        if(ihs==0){puts("");continue;}
        int top=-1,tmp=ihs;
        while(tmp){
            putchar(op[tmp]);
            tmp=pre[tmp];
        }
        puts("");
    }
    return 0;
}

IDA*函数:和A*一样的h()函数,内存占用小是其优势。
#include<cstdio>
#include<cstring>
using namespace std; 
struct S{
    char maze[3][3];
    int x,y;
    int g,h,f;
    S(){}
    S(const S& ts){
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                maze[i][j]=ts.maze[i][j];
            }
        }
        x=ts.x; y=ts.y;
    } 
    void show(){
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                putchar(maze[i][j]);
            }
            puts("");
        }
    }
};
const int pos[][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
inline int ABS(int x){
if(x<0) return-x;
else return x;
}
inline int h(S ts){
    int val=0;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            if(ts.maze[i][j]=='x') continue;
            int c=ts.maze[i][j]-'1';
            val+=ABS(pos[c][0]-i)+ABS(pos[c][1]-j);
        }
    }
    return val;
} 
int fac[]={1,1,2,6,24,120,720,5040,40320};
inline int inv_hash(S ts){
    char str[10]; int ans=0;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            str[i*3+j]=ts.maze[i][j];
            int cnt=0;
            for(int k=i*3+j-1;k>=0;k--){
                if(str[k]>str[i*3+j]) cnt++;
            }
            ans+=fac[i*3+j]*cnt;
        }
    }
    return ans;
} 
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int ans[50],deep;
bool vis[363000];
S ts;
bool dfs(int d){
    if(h(ts)==0) return true;
    if(h(ts)+d>deep) return false;
    int x=ts.x;
    int y=ts.y;
    for(int i=0;i<4;i++){
        int tx=ts.x+dir[i][0];
        int ty=ts.y+dir[i][1];
        if(tx<0||ty<0||tx>=3||ty>=3) continue;
        ts.maze[x][y]=ts.maze[tx][ty];
        ts.maze[tx][ty]='x';
        int tmp=inv_hash(ts);
        if(vis[tmp]){
            ts.maze[tx][ty]=ts.maze[x][y];
            ts.maze[x][y]='x';
            continue;
        }
        vis[tmp]=true;
        ts.x=tx; ts.y=ty;
        ans[d]=i;
        if(dfs(d+1)) return true;
        vis[tmp]=false;
        ts.x=x; ts.y=y;
        ts.maze[tx][ty]=ts.maze[x][y];
        ts.maze[x][y]='x';
    }
    return false;
} 
S s;
bool inv_check(){
    char str[10];
    int cnt=0;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            str[i*3+j]=s.maze[i][j];
            if(str[i*3+j]=='x') continue;
            for(int k=i*3+j-1;k>=0;k--){
                if(str[k]=='x') continue;
                if(str[k]>str[i*3+j]) cnt++;
            }
        }
    }
    return!(cnt&1);
} 
char in[100];
int main(){
    while(gets(in)){
        for(int i=0,x=0,y=0;in[i];i++){
            if((in[i]<='9'&&in[i]>='0')||in[i]=='x'){
                s.maze[x][y]=in[i];
                if(in[i]=='x'){s.x=x;s.y=y;}
                y++;
                if(y==3) y=0,x++;
            }
        }
        if(!inv_check()){ puts("unsolvable"); continue;}
        memset(vis,false,sizeof(vis));
        vis[inv_hash(s)]=true;
        ts=s; deep=0;
        while(true){
            if(dfs(0)) break;
            deep++;
        }
        for(int i=0;i<deep;i++){
            if(ans[i]==0) putchar('d');
            else if(ans[i]==1) putchar('r');
            else if(ans[i]==2) putchar('u');
            else if(ans[i]==3) putchar('l');
        }
        puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值