uva 10422 Knights in FEN

题目地址:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1363

题目描述:

Problem D

Knights in FEN

Input: standard input

Output: standard output

Time Limit: 10 seconds

 

There are black and white knights on a 5 by 5 chessboard. There are twelve of each color, and there is one square that is empty. At any time, a knight can move into an empty square as long as it moves like a knight in normal chess (what else did you expect?).

Given an initial position of the board, the question is: what is the minimum number of moves in which we can reach the final position which is:

Input

First line of the input file contains an integer N (N<14) that indicates how many sets of inputs are there. The description of each set is given below:

Each set consists of five lines; each line represents one row of a chessboard. The positions occupied by white knights are marked by 0 and the positions occupied by black knights are marked by 1. The space corresponds to the empty square on board.

There is no blank line between the two sets of input.

The first set of the sample input below corresponds to this configuration:

Output

For each set your task is to find the minimum number of moves leading from the starting input configuration to the final one. If that number is bigger than 10, then output one line stating

Unsolvable in less than 11 move(s).

otherwise output one line stating

Solvable in n move(s).

where n <= 10.

The output for each set is produced in a single line as shown in the sample output.

Sample Input

2
01011
110 1
01110
01010
00100
10110
01 11
10111
01001
00000

Sample Output

Unsolvable in less than 11 move(s).
Solvable in 7 move(s).


题意:
按照马的走法从源棋盘状态 走到 目标棋盘状态,且在10步以内,并且输出最小步数。
题解:
最小步数,那我肯定倾向于广搜,写出来似乎速度不怎么样,那么记忆化判重就考虑不用线性的了,而是考虑用hash判重我这里用的是BKDR 字符串hash。
所以基本算法就是:
BFS+ BKDR Hash

需要注意的点:
1、由于看题不仔细,以为骑士的走法跟士兵的走法一样是上下左右,结果样例倒腾半天没倒腾出来。(实际上是骑士的走法跟马的走法一样,所以有八个方向可以走)
2、广搜注意是出队的时候处理才能达到广搜的有序性。
3、注意样例之间清空队列和hash表 以及new的节点即时delete掉。
4、注意hash冲突的出来,我这里是链队列处理了。
5、注意10和0的边界数据。

代码:
#include<stdio.h>
#include<string.h>
#define DL 10
#define DI 5
#define MM 1000
#define DD 8
#define HS 1000001//hash size
#define HH 0x7FFFFFFF
int N = 0;
typedef struct node
{
    char mat[DI+5][DI+5];
    int len;
    node * next;
    int x;//the position of ' '
    int y;
    node()
    {
        memset(mat, '\0', sizeof(mat));
        len = 0;
        next = NULL;
    }
}node, * node_link;
node_link min_node = NULL;
node_link target_node = NULL;
node_link head = NULL, rear = NULL;
int dx[DD] = {-2, -2, -1,  1,  2, 2, -1, 1};//8 directions walk
int dy[DD] = {-1,  1, -2, -2, -1, 1,  2, 2};
node_link hash_table[HS + 5];
void delete_pot(node_link & elem)
{
    if(elem != NULL)
    {
        delete elem;
        elem = NULL;
    }
}
void nodelinkcpy(node_link & e1, node_link e2)
{
    if(e2 == NULL) return;
    if(e1 == NULL) e1 = new node();
    for(int i = 0; i <= DI - 1; i++)
        for(int j = 0; j <= DI - 1; j++)
            e1->mat[i][j] = e2->mat[i][j];
    e1->x = e2->x;
    e1->y = e2->y;
    e1->len = e2->len;
    e1->next = e2->next;
}
bool is_mat_equal(node_link e1, node_link e2)
{
    if(e1 == NULL || e2 == NULL) return false;
    for(int i = 0; i <= DI - 1; i++)
        for(int j = 0; j <= DI - 1; j++)
            if(e1->mat[i][j] != e2->mat[i][j])
                return false;
    return true;
}
int bkdr_hash(node_link elem)
{
    if(elem == NULL) return -1;
    int seed_value = 131;
    int hash_value = 0;
    for(int i = 0; i <= DI - 1; i++)
        for(int j = 0; j <= DI - 1; j++)
            hash_value = hash_value * seed_value + elem->mat[i][j];
    return (hash_value & HH) % HS;
}
bool is_vis(node_link elem)
{
    int ind = bkdr_hash(elem);
    if(hash_table[ind] == NULL)
    {
        //add the new hash elem
        node_link new_ele = NULL;
        nodelinkcpy(new_ele, elem);
        new_ele->next = NULL;
        hash_table[ind] = new_ele;
        return false;
    }
    else
    {
        node_link hhead = hash_table[ind];
        node_link pot = hhead;
        while(pot != NULL)
        {
            if(is_mat_equal(pot, elem)) return true;//find it in hash table
            pot = pot->next;
        }
        //not find it , then the elem is conflict hash elem
        node_link new_ele = NULL;
        nodelinkcpy(new_ele, elem);
        new_ele->next = hash_table[ind];
        hash_table[ind] = new_ele;
        return false;
    }
}
void clear_hash()
{
    for(int i = 0; i <= HS + 5 - 1; i++)
    {
        if(hash_table[i] != NULL)
        {
            node_link pot = hash_table[i];
            while(pot != NULL)
            {
                node_link temp = pot;
                pot = pot->next;
                delete_pot(temp);
            }
            hash_table[i] = NULL;
        }
    }
}
void findxy(node_link elem)
{
    if(elem!=NULL)
        for(int i = 0; i <= DI - 1; i++)
            for(int j = 0; j <= DI - 1; j++)
                if(elem->mat[i][j] == ' ')
                {
                    elem->x = i;
                    elem->y = j;
                    return;
                }
}
void print_mat(node_link elem)
{
    if(elem != NULL)
        for(int i = 0; i <= DI - 1; i++)
            printf("%s\n", elem->mat[i]);
}
bool is_reached(node_link elem)
{
    if(elem == NULL || target_node == NULL) return false;
    if(elem->len > DL) return false;
    for(int i = 0; i <= DI - 1; i++)
        for(int j = 0; j <= DI - 1; j++)
            if(target_node->mat[i][j] != elem->mat[i][j]) return false;
    return true;
}
bool queue_empty()
{
    if(head == NULL && rear == NULL) return true;
    else return false;
}
void push(node_link elem)
{
    if(elem != NULL)
    {
        node_link add_ele = NULL;
        nodelinkcpy(add_ele, elem);
        if(queue_empty())
        {
            head = add_ele;
            rear = add_ele;
        }
        else
        {
            rear->next = add_ele;
            rear = rear->next;
        }
    }
}
node_link pop()
{
    if(queue_empty()) return NULL;
    node_link pop_ele = head;
    head = head->next;
    if(head == NULL) rear = NULL;
    return pop_ele;
}
node_link move_space(node_link old_ele, int tx, int ty)
{
    if(old_ele == NULL) return NULL;
    if(tx < 0 || ty < 0 || tx > DI - 1 || ty > DI - 1) return NULL;
    node_link new_ele = NULL;
    nodelinkcpy(new_ele, old_ele);
    char temp = new_ele->mat[new_ele->x][new_ele->y];
    new_ele->mat[new_ele->x][new_ele->y] = new_ele->mat[tx][ty];
    new_ele->mat[tx][ty] = temp;
    new_ele->x = tx;
    new_ele->y = ty;
    new_ele->len = old_ele->len + 1;
    new_ele->next = NULL;
    return new_ele;
}
void queue_clear()
{
    if(!queue_empty())
    {
        node_link pot = head;
        while(pot!=NULL)
        {
            node_link tmp = pot;
            pot = pot->next;
            delete_pot(tmp);
        }
    }
    head = rear = NULL;
}
int main()
{
    target_node = new node();
    strcpy(target_node->mat[0],"11111");
    strcpy(target_node->mat[1],"01111");
    strcpy(target_node->mat[2],"00 11");
    strcpy(target_node->mat[3],"00001");
    strcpy(target_node->mat[4],"00000");
    scanf("%d",&N);
    while(N--)
    {
        node_link in_node = new node();
        for(int i = 0; i <= DI - 1; i++)
        {
            char instr[100];
            fgets(instr, 100, stdin);//note the input include the ' ' can not use scanf("%s")
            while(instr[0] == '\n') fgets(instr, 100, stdin);
            if(instr[strlen(instr) - 1] == '\n') instr[strlen(instr) - 1] = '\0';
            strcpy(in_node->mat[i], instr);
        }
        findxy(in_node);
        if(is_reached(in_node))
        {
            printf("Solvable in %d move(s).\n", 0);
            delete_pot(in_node);
            continue;
        }
        if(!is_vis(in_node)) push(in_node);
        delete_pot(in_node);
        while(!queue_empty())
        {
            node_link center = pop();
            if(is_reached(center)) 
            {
                nodelinkcpy(min_node, center);
                delete_pot(center);
                break;
            }
            //move the space to 8 directions to move space
            for(int i = 0; i <= DD - 1; i++)
            {
                node_link moved = move_space(center, center->x + dx[i], center->y + dy[i]);
                if(moved != NULL && moved->len <= DL && !is_vis(moved)) push(moved);
                delete_pot(moved);
            }
            delete_pot(center);
        }
        if(min_node == NULL) printf("Unsolvable in less than 11 move(s).\n");
        else printf("Solvable in %d move(s).\n", min_node->len);
        delete_pot(min_node);
        queue_clear();
        clear_hash();
    }
    return 0;
}










猜你喜欢

转载自blog.csdn.net/hackerwin7/article/details/43731877
今日推荐