八数码经典

POJ1077.Eight
题目链接


题意:八数码问题,具体看题;


题目类型:广搜经典:(一个bug找了两天。。)

题解0:起初想通过map<struct dd,struct dd >瞎搞,发现map不能用结构体做KEY值,搜到了重载运算,用结构体做KEY值的方法,不懂。。还是记一下;

Code:

struct eight{//这招记下来...少用
//int a[9];数组也不能做键值
int sum;
int dirc;
int pz;
   bool operator<(const struct eight & other) const {
        if (this->sum < other.sum) return true;
        if (this->dirc < other.dirc) return true;
        if (this->pz < other.pz) return true;
        return false;
   }
}M,goal;

题解1:通过一个函数将整个的状态映射到一个数上,将x所在位置用0表示,初步思路f(a)=a1*10+a2*100+a3*1000+a4*10000+a5*100000+....a9*1000000000;

然后广搜时,注意各种细节。。。这搜索太mmp了,以后要多刷这种题磨练意志;然而还是没过mle+tle;

Code:

//改进做法tle
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<time.h>
#define ll long long

using namespace std;
int a[9];
char res[1005];
map<int,char> c;
map<int,int> pre;
map<int,int> vist;

int getidex(int*a)
{
    int uu=0;
    for(int i=0; i<9; i++)
    {
        uu=uu*10+a[i];
    }
    return uu;
}

void getnode(int m)
{
    int k=8;
    memset(a,0,sizeof(a));
    while(k>=0)
    {
        a[k]=m%10;
        m/=10;
        k--;
    }
}

void debug()
{
    for(int i=0; i<3; i++)
    {
        for(int j=0; j<3; j++)
        {
            printf("%d ",a[i*3+j]);
        }
        printf("\n");
    }
    system("pause");
}

void BFS(int n)
{
    int k,t=n,p;
    queue<int> q;
    q.push(n);

//    for(int i=0;i<9;i++)
//    printf("%d ",a[i]);
//    printf("\n");
    	 k=getidex(a);
 	pre[k]=-1;
    	vist[k]=1;


    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        getnode(u);


        for(int j=0; j<9; j++)
            if(a[j]==0)
            {
                p=j;
                break;
            }


        //printf("zp-->|%d\n",p);


        if(p<6)
        {
            swap(a[p],a[p+3]);
            k=getidex(a);
            //printf("d-->k//%d\n",k);
            //debug();


            if(!vist[k])
            {
                vist[k]=1;
                pre[k]=u;
                c[k]='d';
                q.push(k);
            }
            swap(a[p],a[p+3]);
        }

        if(p%3)
        {
            swap(a[p-1],a[p]);
            k=getidex(a);

            //printf("l-->k//%d\n",k);
            //debug();

            if(!vist[k])
            {
                vist[k]=1;
                pre[k]=u;
                c[k]='l';
                q.push(k);
            }

            swap(a[p],a[p-1]);
        }

        if(p%3<2)
        {
            swap(a[p+1],a[p]);
            k=getidex(a);

            //printf("r-->k//%d\n",k);
            //debug();

            if(!vist[k])
            {
                vist[k]=1;
                pre[k]=u;
                c[k]='r';
                q.push(k);
            }

            swap(a[p],a[p+1]);
        }
        if(p>2)
        {
            swap(a[p-3],a[p]);
            k=getidex(a);

            //printf("u-->k//%d\n",k);
            //debug();

            if(!vist[k])
            {
                vist[k]=1;
                pre[k]=u;
                c[k]='u';
                q.push(k);
            }
            swap(a[p],a[p-3]);

        }
        if(vist[123456780])break;
    }
    if(vist[123456780])
    {
        int u=123456780,x=u,cnt=0;
        while(x!=-1)
        {
            //printf("%d %c\n",cnt,c[x]);
            res[cnt++]=c[x];
            x=pre[x];
        }
        for(int i=cnt-2; i>=0; i--)
        {
            printf("%c",res[i]);
        }
        printf("\n");
    }
    else
        printf("unsolvable\n");
}


int main()
{
    int uu=0;
    for(int i=0; i<9; i++)
    {
        char c;
        scanf(" %c",&c);
        if(c=='x'||c=='X')
        {
            a[i]=0;
            uu=uu*10;
        }
        else
        {
            a[i]=c-'0';
            uu=uu*10+a[i];
        }
    }
//    for(int i=0;i<9;i++)printf(" %d",a[i]);
//    printf("\n");


    //printf("uu//%d\n",uu);
    // time_t ts,te;
    //ts=time(NULL);
    BFS(uu);
    //te=time(NULL);
    //printf("%ld\n",te-ts);
    //system("pause");
    return 0;
}  

题解2;看了大神题解知道了康托展开,X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!,可以很大程度上减小数据的大小,就不用map了;
Code:

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<time.h>
#define ll long long

using namespace std;

int vis[362880];
int fa[362880];
char step[362880];
int fac[]={1,1,2,6,24, 120, 720, 5040, 40320, 362880};
int dir[4][2] = {{-1, 0}, {1,0}, {0, -1}, {0, 1}}; //u, d, l, r
struct node
{
    char s[9];
    int space;
};

int Hash(const char* str)
{
    int n=9,num=0,temp;
    for(int i=0;i<n-1;i++)
    {
        temp=0;
        for(int j=i+1;j<n;j++)
        {
            if(str[i]>str[j])temp++;
        }
        num+=temp*fac[str[i]-1];
    }
    return num;
}

void get_node(int num, node &temp)
{
    int n=9;
    int a[9];
    for(int i=2;i<=n;i++)
    {
        a[i-1]=num%i;
        num/=i;
        temp.s[i-1]=0;
    }

    temp.s[0]=0;
    int rn,i;
    for(int k=n;k>=2;k--)
    {
        rn=0;
        for(i=n-1;i>=0;i--)
        {
            if(temp.s[i]!=0)
                continue;
            if(rn==a[k-1])
                break;
            rn++;
        }
        temp.s[i]=k;
    }
    for(int i=0;i<n;i++)
    {
        if(temp.s[i]==0)
        {
            temp.s[i]=1;
            break;
        }
    }
    temp.space=n-a[n-1]-1;
}

void bfs(const node&begin)
{
   memset(vis, 0, sizeof(vis));
    int u = Hash(begin.s);
    vis[u] = 1;
    fa[u] = -1;//便于后续输出路径,保存了每一步的父节点

    queue<int> q;
    q.push(u);

    node now,next;
    while(!q.empty())
    {
       u = q.front();
        q.pop();

        get_node(u, now);

        int k = now.space;
        int x = k/3;
        int y = k%3;

        for(int i=0;i<4;i++)
        {
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            if(xx>=0&&xx<=2&&yy>=0&&yy<=2)//yy写成y。。。RE好几年
            {
                next=now;
                next.space=xx*3+yy;
                swap(next.s[k],next.s[next.space]);
                int v=Hash(next.s);
                if(!vis[v])
                {
                    vis[v]=1;
                    step[v]=i;
                    fa[v]=u;
                    if(v==0)//
                    {
                        return;
                    }
                    q.push(v);
                }
            }
        }
    }
}

void print()
{
    int n, u;
    char path[1000];
    n = 1;
    path[0] = step[0];
    u = fa[0];
    while(fa[u]!=-1)
    {
        path[n] = step[u];
        ++n;
        u = fa[u];
    }

    for(int i=n-1; i>=0; --i)
    {
        if(path[i]==0)
            cout << "u";
        else if(path[i]==1)
            cout << "d";
        else if(path[i]==2)
            cout << "l";
        else
            cout << "r";
    }
}

int main()
{
    char c;
    node start;
    for(int i=0;i<9;i++)
    {
        scanf(" %c",&c);
        if(c=='x')
        {
            start.s[i]=9;
            start.space=i;
        }
        else
        {
            start.s[i]=c-'0';
        }
    }

    bfs(start);

    if(vis[0]==1)
        print();
    else
        cout << "unsolvable";
    cout << endl;

    return 0;
}


题解*:大佬题解上讲的,看了只觉得好强,我们要的最后一个状态是{1, 2, 3, 4, 5, 6, 7, 8, x}, 这个排列的逆序数是0,
是偶数。而对于任意一个排列,显然,因为x不表示数字,那么也就是说把x向左右两个方向移动并不会改变整个序列
的逆序数,那么有结论;如果初始序列的逆序数是一个奇数,则必然这个序列无解(必要,不充分)


题解**:还有其他做法双向搜索,A*,IDA*(都不会。。。以后补上Orz)





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值