码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1043 Eight

时间:2014-09-16 17:21:40      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:康托展开   bfs   二分   

八数码问题。


BFS+康托展开。康托用来判重。直接搜的的话会超时。需要预处理。


我就用结构体存了一个状态。

struct lx
{
    int can;//当前状态的康托展开
    int pcan;//上一状态的康托展开
    int k;//移动方向
};

把所有的 181442 种状态存下来。排序,然后二分搜索。迭代寻找上一状态,直到初始的 0 。


开始写的时候估计康托逆展开有点问题,一直WA。重写之后就莫名其妙的1A了。


G++ 171ms

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<stack>
#include<iostream>
#include<list>
#include<set>
#include<cmath>

#define INF 0x7fffffff
#define eps 1e-8
#define LL long long
#define PI 3.141592654
#define CLR(a,b) memset(a,b,sizeof(a))
#define FORi(n) for(int i=0;i<n;i++)
#define FORj(n) for(int j=0;j<n;j++)
#define FORk(n) for(int k=0;k<n;k++)
#define debug puts("==fuck==")
#define acfun std::ios::sync_with_stdio(false)

#define SIZE 1000+10
using namespace std;

struct lx
{
    int can;
    int pcan;
    int k;
};
int g[4][4]={{1,2,3},{4,5,6},{7,8,9}};
int fac[]={1,1,2,6,24,120,720,5040,40320};

int xx[]={0,0,-1,1};
int yy[]={1,-1,0,0};
lx q[200000];   //max = 181441
bool vis[500000];   //max = 362879
int n;

int cantor()
{
    int tmp[10],top=0,num=0;
    FORi(3)
    FORj(3)
    tmp[top++]=g[i][j];
    FORi(top)
    {
        int t=0;
        for(int j=i+1;j<top;j++)
            if(tmp[j]<tmp[i])t++;
            num+=fac[top-i-1]*t;
    }
    return num;
}
int uncantor(int num)
{
    int tmp[10],top=0;
    bool v[10];
    CLR(v,0);
    for(int i=1;i<=9;i++)
    {
        int t=num/fac[9-i];
        num-=t*fac[9-i];
        int j=1,k=0;
        for(;k<=t;j++)
            if(!v[j])k++;
        j--;
        v[j]=1;
        tmp[i-1]=j;
    }
    int k=0,site;
    FORi(3)
    FORj(3)
    {
        g[i][j]=tmp[k++];
        if(g[i][j]==9)site=i*3+j;
    }
    return site;
}

void bfs()
{
    int h=0,e=0;
    q[h].can=cantor();
    q[h].pcan=-1;
    q[h++].k=-1;
    CLR(vis,0);
    vis[0]=1;
    while(e<h)
    {
        int can=q[e++].can;
        int site=uncantor(can);
        int i=site/3;
        int j=site%3;
        for(int k=0; k<4; k++)
        {
            int x=i+xx[k];
            int y=j+yy[k];
            if(x>=3||x<0||y>=3||y<0)continue;
            swap(g[i][j],g[x][y]);
            int tmp=cantor();
            swap(g[i][j],g[x][y]);
            if(vis[tmp])continue;
            vis[tmp]=1;
            q[h].can=tmp;
            q[h].pcan=can;
            q[h++].k=k;
            n=h;
        }
    }
}
bool cmp(lx a,lx b)
{
    return a.can<b.can;
}
int half(int left,int right,int key)
{
    int l=left,r=right;
    while(l<r)
    {
        int m=(l+r)>>1;
        if(q[m].can==key)return m;
        else if(q[m].can>key)r=m;
        else l=m+1;
    }
    return -2;
}
int main()
{
    bfs();
    sort(q,q+n,cmp);
    char str[11];
    while(~scanf("%s",str))
    {
        if(str[0]>='0'&&str[0]<='8')
            g[0][0]=str[0]-'0';
        else
            g[0][0]=9;
        for(int i=1; i<9; i++)
        {
            scanf("%s",str);
            if(str[0]>='0'&&str[0]<='8')
                g[i/3][i%3]=str[0]-'0';
            else
                g[i/3][i%3]=9;
        }
        int can=cantor();
        char out[1001];
        int top=0;
        bool flag=0;
        while(can!=-1)
        {
            int k=half(0,n,can);
            if(k==-2)
            {
                flag=1;
                break;
            }
            if(q[k].k==0)
                out[top++]='l';
            else if(q[k].k==1)
                out[top++]='r';
            else if(q[k].k==2)
                out[top++]='d';
            else
                out[top++]='u';

            can=q[k].pcan;
        }
        if(flag)
        puts("unsolvable");
        else
        {
            out[top-1]='\0';
            puts(out);
        }
    }
}


HDU 1043 Eight

标签:康托展开   bfs   二分   

原文地址:http://blog.csdn.net/dongshimou/article/details/39319895

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!