HDU 3567 Eight II 八数码(2)

Eight-puzzle, which is also called "Nine grids", comes from an old game. 

In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an 'X'. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of 'X' with one tile. 

We use the symbol 'r' to represent exchanging 'X' with the tile on its right side, and 'l' for the left side, 'u' for the one above it, 'd' for the one below it. 

 

A state of the board can be represented by a string S using the rule showed below. 

 

The problem is to operate an operation list of 'r', 'u', 'l', 'd' to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains: 
1. It is of minimum length among all possible solutions. 
2. It is the lexicographically smallest one of all solutions of minimum length. 
InputThe first line is T (T <= 200), which means the number of test cases of this problem. 

The input of each test case consists of two lines with state A occupying the first line and state B on the second line. 
It is guaranteed that there is an available solution from state A to B. 
OutputFor each test case two lines are expected. 

The first line is in the format of "Case x: d", in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
S is the operation list meeting the constraints and it should be showed on the second line. 
Sample Input
2
12X453786
12345678X
564178X23
7568X4123
Sample Output
Case 1: 2
dd
Case 2: 8
urrulldr


题意:8数码的进阶版,这次是从A状态到达B状态确保一定有解。

嗯,表示A*算法过不了这题的,估计是数据比较多的那种。

注意:上一次的8数码的问题,只是要找到一个解就可以,所以A*算法的优化有两个权值函数h和g。并不影响最后的结果。因为只需要最快找到解就可以。

但是这一次不一样,你需要找到一个步数最少的解,你可以理解为g最小,然后还是要字典序最小的,你只需要调整一下搜索顺序就可以了。

附上一下A*这里启发式函数用的曼哈顿距离。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
const int inf = 1e8;
const int MAXN = 4e5;
int n,m;
int temp[10];
int x[10],y[10];
int aim;
char step[4] = {'d','l','r','u'};
int dx[4] = {1,0,0,-1};
int dy[4] = {0,-1,1,0};
int fac[9]= {1,1,2,6,24,120,720,5040,40320}; //康拖展开判重
int vis[MAXN];
int pre[MAXN];
//得到状态
int get_state(int *s)
{
    int sum=0;
    for(int i=0; i<9; i++)
    {
        int num=0;
        for(int j=i+1; j<9; j++)
            if(s[j]a.f;
    }
};

void bfs(node x)
{
    memset(vis,-1,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    priority_queueq;
    q.push(x);
    vis[x.state] = 1;
    while(!q.empty())
    {
        node u = q.top();
        q.pop();
        if(u.state == aim)
        {
            string ans;
            while(u.state != -1)
            {
                ans += step[vis[u.state]];
                u.state = pre[u.state];
            }
            printf("%d\n",ans.size()-1);
            for(int i = ans.size()-2 ; i >= 0 ; --i)printf("%c",ans[i]);
            puts("");
            return ;
        }
        //4种交换
        int x = u.pos/3;
        int y = u.pos%3;
        for(int i = 0 ; i < 4; ++i)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3)
            {
                node v = u;
                swap(v.num[u.pos],v.num[nx*3+ny]);
                v.state = get_state(v.num);

                if(vis[v.state] == -1)
                {
                    v.pos = nx*3+ny;
                    v.g++;
                    v.h = get_h(v.num);
                    v.f = v.g + v.h;

                    vis[v.state] = i;
                    pre[v.state] = u.state;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    int t,ca = 0;
    char s[15];
    scanf("%d",&t);
    while(t--)
    {
        node u;
        scanf("%s",s);
        for(int i = 0 ; i < 9; ++i)
        {
            if(s[i] == 'X')
            {
                u.num[i] = 0;
                u.pos = i;
            }
            else u.num[i] = s[i] - '0' ;
        }
        u.state = get_state(u.num);
        u.g = 0;
        u.h = get_h(u.num);
        u.f = u.g + u.h;

        scanf("%s",s);
        for(int i = 0 ; i < 9 ; ++i)
        {
            if(s[i] == 'X')temp[i] = 0;
            else temp[i] = s[i] - '0' ;
        }
        aim = get_state(temp);
        for(int i = 0 ;i < 9 ; ++i)
        {
            x[temp[i]] = i/3;
            y[temp[i]] = i%3;
        }
        ca++;
        printf("Case %d: ",ca);
        bfs(u);
    }
    return 0;
}

然而是TLE的,可能是组数比较多的那种。上面一个题也不难想到一种预处理的办法,但是内存限制了一半。

然后这个题采用预处理的办法用了33196KB。所以上一题预处理会超内存。

这个题A*不可过,预处理则可以。不过估计双向bfs(划掉)也可破。字典序啊喂,双向bfs根本无法控制的好吧。什么可破啊,我试了一晚上最终发现这根本不可控QAQ。因为前半字典序最小+后半字典序最小不等于前半加后半字典序最小!!!!!!!譬如说aaaaab和aaabba的例子

你会输出aaabba,实际上最好的则是aaaaab。


预处理:这里你需要知道其实每个串无非就9种情况,只与X的位置有关,其余的你可以直接做一个映射关系。

char eight_num[9][10] = {"X12345678" , "1X2345678" ,  "12X345678" , "123X45678" ,
                        "1234X5678" , "12345X678" , "123456X78" , "1234567X8" , "12345678X" };

这里就是基本的9种情况,然后我们做一个映射就可以了。

比如说示例1中的

12X453786
我们就可以做这样的一个映射“12X345678”

分别是:1 → 1,2 → 2,X → X,4 → 3,5 → 4,3 → 5,7 → 6,8 → 7,6 → 8,

这样我们只需要搜索8种基本状态记录路径就可以了。

然后目标状态一样要映射掉。

这样就可以得到答案了。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
const int inf = 1e8;
const int MAXN = 4e5;
int n,m;
char eight_num[9][10] = {"X12345678" , "1X2345678" ,  "12X345678" , "123X45678" ,
                        "1234X5678" , "12345X678" , "123456X78" , "1234567X8" , "12345678X" };


char step[4] = {'d','l','r','u'};
int dx[4] = {1,0,0,-1};
int dy[4] = {0,-1,1,0};
int fac[9]= {1,1,2,6,24,120,720,5040,40320}; //康拖展开判重
int vis[9][MAXN];
int pre[9][MAXN];
//得到状态
int get_state(int *s)
{
    int sum=0;
    for(int i=0; i<9; i++)
    {
        int num=0;
        for(int j=i+1; j<9; j++)
            if(s[j]= 0 ; --i)printf("%c",ans[i]);
    puts("");
}

void bfs(node x,int kind)
{
    queueq;
    q.push(x);
    vis[kind][x.state] = 1;
    while(!q.empty())
    {
        node u = q.front();
        q.pop();

        //4种交换
        int x = u.pos/3;
        int y = u.pos%3;
        for(int i = 0 ; i < 4; ++i)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3)
            {
                node v = u;
                swap(v.num[u.pos],v.num[nx*3+ny]);
                v.state = get_state(v.num);

                if(vis[kind][v.state] == -1)
                {
                    v.pos = nx*3+ny ;
                    vis[kind][v.state] = i;
                    pre[kind][v.state] = u.state;
                    q.push(v);
                }
            }
        }
    }
}

void init(char *s,int kind)//预处理
{
    node u;
    for(int i = 0 ; i < 9; ++i)
    {
        if(s[i] == 'X')
        {
            u.num[i] = 0;
            u.pos = i;
        }
        else u.num[i] = s[i] - '0' ;
    }
    u.state = get_state(u.num);
    bfs(u,kind);
}
int main()
{
    int t,ca = 0;
    char s[15],c[15];
    int temp[MAXN];
    int kind;
    memset(vis,-1,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i = 0 ;i < 9 ; ++i)init(eight_num[i],i);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s);
        int cnt = 1;
        //设置映射初始状态8数码
        for(int i = 0 ;i < 9 ; ++i)
        {
            if(s[i] == 'X')
            {
                c[0] = 0;
                kind = i;
            }
            else c[s[i] - '0'] = cnt++;
        }
        //映射目标8数码
        scanf("%s",s);
        for(int i = 0 ; i < 9 ; ++i)
        {
            if(s[i] == 'X')temp[i] = c[0];
            else temp[i] = c[s[i] - '0'] ;
        }

        int aim = get_state(temp);//得到目标状态
        ca++;
        printf("Case %d: ",ca);
        print(aim,kind);
    }
    return 0;
}








你可能感兴趣的:(广度优先搜索)