菜鸟系列——八数码八境界

菜鸟就要老老实实重新学起:

八数码:

很经典的搜索问题,写这个练练搜索。

八数码问题就是给出一个3*3的矩阵其中有1~8数字和一个空格‘x’,可以移动周围的数字到这个空格上,要求某种排列恢复到{ {1,2,3},{4,5,6},{7,8,x}}形式的移动方法。

由大神的八数码八境界想自己实现一下 http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html

一、暴力BFS+STL

就是直接暴力bfs所有的询问,string储存当前状态,vector<int>储存当前路径,map判重,好写,但时间感人。

代码:

#define N 512345

char s[101];
struct node
{
    string str;
    vector<int>res;
    int index;
};
map<string,int> mp;
vector<int>res;

bool bfs(string ss)
{
    char c;
    queue<node> q;
    while(!q.empty())q.pop();
    node g,h;
    g.str="12345678x";g.res.clear();g.index=8;
    q.push(g);
    while(!q.empty())
    {
        g=q.front();q.pop();
        if(g.str==ss)
        {
            res=g.res;
            return true;
        }
        h=g;
        if((h.index+1)%3!=0)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
            h.index++;
            h.res.push_back(4);
            if(mp[h.str]==0)
            {
                mp[h.str]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index%3!=0)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
            h.index--;
            h.res.push_back(3);
            if(!mp[h.str])
            {
                mp[h.str]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index<6)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
            h.index+=3;
            h.res.push_back(2);
            if(!mp[h.str])
            {
                mp[h.str]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index>2)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
            h.index-=3;
            h.res.push_back(1);
            if(!mp[h.str])
            {
                mp[h.str]=true;
                q.push(h);
            }
        }
    }
    return false;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%s",s)!=EOF)
    {
        mp.clear();
        for(i=1;i<9;i++)
            scanf("%s",s+i);
        string ss(s);
        if(bfs(ss))
            for(i=res.size()-1;i>=0;i--)
            {
                if(res[i]==1)printf("d");
                if(res[i]==2)printf("u");
                if(res[i]==3)printf("r");
                if(res[i]==4)printf("l");
            }
        else
            printf("unsolvable");
        printf("\n");
    }
    return 0;
}


二、暴力BFS+hash判重

与上一方法基本相同,就是减少stl的使用,改用char[]存状态,用康托展开计算全排列数值从而得到哈希值判重。

能够有效缩减时间,但是询问多时尤其是在无解时耗时依然较多。

关于康托展开:http://blog.csdn.net/kopyh/article/details/48377291


代码:

#define N 512345

char ss[10];
struct node
{
    char str[10];
    vector<int>res;
    int index,hashnum;
};
vector<int>res;
bool vis[N];
int  fac[] = {1,1,2,6,24,120,720,5040,40320};
int over;
int KT(char ss[])
{
    int i, j, t, sum;
    int s[10];
    for(i=0;i<9;i++)
    {
        if(ss[i]=='x')
            s[i]=0;
        else
            s[i]=ss[i]-'0';
    }
    sum = 0;
    for (i=0; i<9; i++)
    {
        t = 0;
        for (j=i+1; j<9; j++)
            if (s[j] < s[i])
                t++;
        sum += t*fac[9-i-1];
    }
    return sum+1;
}
bool bfs(char ss[])
{
    char c;
    queue<node> q;
    while(!q.empty())q.pop();
    over = KT(ss);
    node g,h;
    for(int i=0;i<8;i++)
        g.str[i]=i+1+'0';
    g.str[8]='x';g.str[9]='\0';
    g.res.clear();g.index=8;
    q.push(g);
    while(!q.empty())
    {
        g=q.front();q.pop();
        if(KT(g.str)==over)
        {
            res=g.res;
            return true;
        }
        h=g;
        if((h.index+1)%3!=0)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
            h.index++;
            h.res.push_back(4);
            int t=KT(h.str);
            if(!vis[t])
            {
                vis[t]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index%3!=0)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
            h.index--;
            h.res.push_back(3);
            int t=KT(h.str);
            if(!vis[t])
            {
                vis[t]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index<6)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
            h.index+=3;
            h.res.push_back(2);
            int t=KT(h.str);
            if(!vis[t])
            {
                vis[t]=true;
                q.push(h);
            }
        }
        h=g;
        if(h.index>2)
        {
            c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
            h.index-=3;
            h.res.push_back(1);
            int t=KT(h.str);
            if(!vis[t])
            {
                vis[t]=true;
                q.push(h);
            }
        }
    }
    return false;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%s",ss)!=EOF)
    {
        memset(vis,false,sizeof(vis));
        for(i=1;i<9;i++)
            scanf("%s",ss+i);
        if(bfs(ss))
            for(i=res.size()-1;i>=0;i--)
            {
                if(res[i]==1)printf("d");
                if(res[i]==2)printf("u");
                if(res[i]==3)printf("r");
                if(res[i]==4)printf("l");
            }
        else
            printf("unsolvable");
        printf("\n");
    }
    return 0;
}

三、暴力BFS+hash判重 +打表

与上一方法基本相同,就是改成一次BFS所有可能进行打表,时间可以保持在200ms内解决问题。


代码:

#define N 512345

char ss[10];
struct node
{
    char str[10];
    vector<int>res;
    int index,num;
};
vector<int>res[N];
bool vis[N];
int  fac[] = {1,1,2,6,24,120,720,5040,40320};
int over;
int ans[N];
int KT(char ss[])
{
    int i, j, t, sum;
    int s[10];
    for(i=0;i<9;i++)
    {
        if(ss[i]=='x&#
  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值