Chinaunix首页 | 论坛 | 博客
  • 博客访问: 71334
  • 博文数量: 41
  • 博客积分: 1475
  • 博客等级: 上尉
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-27 22:49
文章分类
文章存档

2012年(8)

2011年(1)

2009年(32)

我的朋友
最近访客

分类:

2009-04-16 20:43:14

/*
 * UVA Problem ID: 10181.
 * Use A* Algorithm to solve 15-puzzle problem.
 * Xiaofeng Ye
 */


#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

char result_board[4][4] = {
    1, 2, 3, 4,
    5, 6, 7, 8,
    9, 10, 11, 12,
    13, 14, 15, 0
};

typedef struct _position {
    char x;
    char y;
} position;

position result_instance_pos[16] = {
    {3,3},
    {0,0}, {0,1}, {0,2}, {0,3},
    {1,0}, {1,1}, {1,2}, {1,3},
    {2,0}, {2,1}, {2,2}, {2,3},
    {3,0}, {3,1}, {3,2}
};
int calculate_h_value(char board[4][4])
{
    int i, j;
    char unit;
    int h_value = 0;

    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            unit = board[i][j];
            h_value += abs(i-result_instance_pos[unit].x) +
                       abs(j-result_instance_pos[unit].y);
            //printf("%d ", abs(i-result_instance_pos[unit].x) +

            // abs(j-result_instance_pos[unit].y));

        }
    }
    //printf("\n");


    return h_value;
}

enum DIRECTION {
    UP = 0,
    RIGHT,
    DOWN,
    LEFT,
};

typedef struct _board_instance {
    int g_value;
    int h_value;
    char board[4][4];
    char where;
    position zero_pos;
    struct _board_instance *parent;
    struct _board_instance *next;
} board_instance, instance_list;

board_instance *final_instance = NULL;

int is_board_instance_same(board_instance *ins1, board_instance *ins2)
{
    if (0 == memcmp(ins1->board, ins2->board, 16)) {
        return 1;
    } else {
        return 0;
    }
}

#define FVALUE(ins) ( ins->h_value + ins->g_value )

void show_instance(board_instance *ins)
{
    int i, j;
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            printf("%d\t", ins->board[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int is_possible(char board[4][4])
{
    char *p_unit = (char *)board;
    int i;
    int j;
    int n_inverse = 0;
    int zero_index;

    for (i = 0; i < 16; i++) {
        if (*(p_unit+i) == 0) {
            zero_index = i;
            continue;
        }
        for (j = i+1; j < 16; j++) {
            if (*(p_unit+j) != 0 && *(p_unit+j) < *(p_unit+i)) {
                n_inverse++;
            }
        }
    }

    n_inverse += zero_index/4 + 1;

    if (n_inverse % 2 == 0) {
        return 1;
    } else {
        return 0;
    }
}

instance_list *instance_list_add_front(instance_list *list, board_instance *instance)
{
    if (NULL == list) {
        list = instance;
        list->next = NULL;
        return list;
    } else {
        instance->next = list->next;
        list->next = instance;
        return instance;
    }
}

board_instance *instance_list_get_smallest(instance_list *list)
{
    board_instance *instance = list;
    board_instance *cursor = list;

    while (cursor->next != NULL) {
        cursor = cursor->next;
        if ((cursor->g_value + cursor->h_value) <
            (instance->g_value + instance->h_value)){
            instance = cursor;
        }
    }
    return instance;
}

board_instance *board_instance_new(char board[4][4])
{
    board_instance *new_instance;
    char *p_unit = (char *)board;
    int i;

    for (i = 0; i < 16; i++) {
        if (*p_unit++ == 0) {
            break;
        }
    }
    if (16 == i) {
        return NULL;
    }

    new_instance = (board_instance *)malloc(sizeof(board_instance));
    new_instance->g_value = 0;
    memcpy(new_instance->board, board, 16);
    new_instance->parent = NULL;
    new_instance->next = NULL;
    new_instance->zero_pos.x = i / 4;
    new_instance->zero_pos.y= i % 4;
    new_instance->h_value = calculate_h_value(new_instance->board);

    return new_instance;
}

board_instance *board_instance_new_child(board_instance *parent, enum DIRECTION where)
{
    board_instance *child;
    char tmp_val;
    position old_pos = parent->zero_pos;

    child = (board_instance *)malloc(sizeof(board_instance));
    memcpy(child, parent, sizeof(board_instance));
    child->g_value++;
    child->next = NULL;
    child->parent = parent;
    switch (where) {
    case UP:
        child->zero_pos.x--;
        child->where = 'U';
        break;
    case RIGHT:
        child->zero_pos.y++;
        child->where = 'R';
        break;
    case DOWN:
        child->zero_pos.x++;
        child->where = 'D';
        break;
    case LEFT:
        child->zero_pos.y--;
        child->where = 'L';
        break;
    default:
        /* NOTREACHED */
        assert(0);
    }
    tmp_val = child->board[child->zero_pos.x][child->zero_pos.y];
    child->board[child->zero_pos.x][child->zero_pos.y] = 0;
    child->board[old_pos.x][old_pos.y] =tmp_val;

    child->h_value = calculate_h_value(child->board);
    return child;
}

void init_h_value(board_instance *instance)
{
}

instance_list *open_list = NULL;
instance_list *close_list = NULL;

int close_list_find(board_instance *ins)
{
    board_instance *cursor = close_list;
    while (cursor != NULL) {
        if (0 == memcmp(ins->board, cursor->board, 16)) {
            return 1;
        }
        cursor = cursor->next;
    }

    return 0;
}

void close_list_add(board_instance *ins)
{
    if (NULL == close_list) {
        close_list = ins;
        close_list->next = NULL;
    } else {
        ins->next = close_list->next;
        close_list = ins;
    }
}

void open_list_add(board_instance *ins)
{
    board_instance *cursor = open_list;
    board_instance *pre_cursor = open_list;

    if (NULL == open_list) {
        open_list = ins;
        return;
    } else {
        if (is_board_instance_same(ins, cursor)) {
            if (FVALUE(ins) < FVALUE(cursor)) {
                ins->next = cursor->next;
                free(cursor);
            }
            return;
        }
        cursor = cursor->next;
        while (cursor != NULL) {
            if (is_board_instance_same(ins, cursor)) {
                if (FVALUE(ins) < FVALUE(cursor)) {
                    ins->next = cursor->next;
                    free(cursor);
                    pre_cursor->next = ins;
                }
                return;
            }
            pre_cursor = cursor;
            cursor = cursor->next;
        }
        pre_cursor->next = ins;
        ins->next = NULL;
    }
}

board_instance *open_list_remove_smallest()
{
    board_instance *smallest = open_list;
    board_instance *pre_smallest = open_list;
    board_instance *pre_cursor = open_list;
    board_instance *cursor = open_list;

    if (NULL == cursor->next) {
        open_list = NULL;
        return smallest;
    } else {
        cursor = cursor->next;
        while (cursor != NULL) {
            if (FVALUE(smallest) > FVALUE(cursor)) {
                smallest = cursor;
                pre_smallest = pre_cursor;
            }
            pre_cursor = cursor;
            cursor = cursor->next;
        }
        if (smallest == open_list) {
            open_list = smallest->next;
        }
        pre_smallest->next = smallest->next;
        smallest->next = NULL;
        return smallest;
    }
}

int is_result_instance(board_instance *ins)
{
    if (0 == memcmp(ins->board, result_board, 16)) {
        //__asm int 3

        return 1;
    } else {
        return 0;
    }
}


/* DEBUG */
void open_list_show()
{
    int i, j;
    board_instance *cursor = open_list;

    printf("-------------------------------------------\n");
    while (cursor != NULL) {
        printf("**************\n");
        printf("g_value+h_value=%d\n", cursor->h_value+cursor->g_value);
        for (i = 0; i < 4; i++) {
            for (j = 0; j < 4; j++) {
                printf("%d\t", cursor->board[i][j]);
            }
            printf("\n");
        }
        cursor = cursor->next;
    }
}

/*
 * Return 0: The open list is empty.
 * Return 1: Expand successfully.
 * Return 2: Reach the end.
 */

int open_list_expand()
{
    board_instance *smallest;
    board_instance *tmp_instance;

    smallest = open_list_remove_smallest();
    if (NULL == smallest) {
        return 0;
    }
    printf("%d\n", smallest->h_value+smallest->g_value);
    show_instance(smallest);
    if (smallest->zero_pos.y != 0) {
        tmp_instance = board_instance_new_child(smallest, LEFT);
        if (is_result_instance(tmp_instance)) {
            final_instance = tmp_instance;
            return 2;
        }
        if (!close_list_find(tmp_instance)) {
            open_list_add(tmp_instance);
        } else {
            free(tmp_instance);
        }
    }
    if (smallest->zero_pos.y != 3) {
        tmp_instance = board_instance_new_child(smallest, RIGHT);
        if (is_result_instance(tmp_instance)) {
            final_instance = tmp_instance;
            return 2;
        }
        if (!close_list_find(tmp_instance)) {
            open_list_add(tmp_instance);
        } else {
            free(tmp_instance);
        }
    }
    if (smallest->zero_pos.x != 0) {
        tmp_instance = board_instance_new_child(smallest, UP);
        if (is_result_instance(tmp_instance)) {
            final_instance = tmp_instance;
            return 2;
        }
        if (!close_list_find(tmp_instance)) {
            open_list_add(tmp_instance);
        } else {
            free(tmp_instance);
        }
    }
    if (smallest->zero_pos.x != 3) {
        tmp_instance = board_instance_new_child(smallest, DOWN);
        if (is_result_instance(tmp_instance)) {
            final_instance = tmp_instance;
            return 2;
        }
        if (!close_list_find(tmp_instance)) {
            open_list_add(tmp_instance);
        } else {
            free(tmp_instance);
        }
    }

    close_list_add(smallest);

    return 1;
}


void show_the_path()
{
    board_instance *ins = final_instance;

    while (ins != NULL) {
        //show_instance(ins);

        //printf("----------------------------\n");

        printf("%c", ins->where);
        ins = ins->parent;
    }
    printf("\n");
}

int main(int argc, char **argv)
{
    char input_board[4][4];
    int val;
    char *p_unit = (char *)input_board;
    int i;
    int rc;
    board_instance *start_instance = NULL;
    board_instance *tmp_instance = NULL;
    board_instance *cur_instance = NULL;

    for (i = 0; i < 16; i++) {
        scanf("%d", &val);
        *(p_unit+i) = (char)val;
    }

    /* DEBUG */
    //printf("%d\n", calculate_h_value(input_board));

    //exit(0);


    if (!is_possible(input_board)) {
        printf("This puzzle is not solvable.\n");
        return 1;
    }

    start_instance = board_instance_new(input_board);
    cur_instance = start_instance;
    open_list_add(cur_instance);

    //open_list_show();

    while (1) {
        rc = open_list_expand();
        //open_list_show();

        if (rc == 0) {
            printf("Open list is empty.\n");
            exit(1);
        }
        if (2 == rc) {
            printf("Get the result.\n");

            show_the_path();
            exit(0);
        }
    }

    return 0;
}

阅读(911) | 评论(0) | 转发(0) |
0

上一篇:ACM UVA (10183)

下一篇:ACM UVA (10182)

给主人留下些什么吧!~~