• 跳舞链解数独


    ---恢复内容开始---

    #include <stdio.h>
    #include <malloc.h>
    #include <time.h>
    typedef struct DLX_node//节点定义
    {
        struct DLX_node* up;
        struct DLX_node* down;
        struct DLX_node* left;
        struct DLX_node* right;
        int is_head;
        int index;
    }d_node,*pd_node;
    int row = 0;
    struct node_heap
    {
        int cul_value;
        int position_index;
    };
    pd_node head;
    pd_node* p_head;
    pd_node stack[81];
    int stack_index = 0;
    struct node_heap mutual_index[324];
    int current_heap_number = 323;
    int available_column = 323;
    int position_index[324];
    #define shift_base 0x80000000
    int a[9][9] = { {8,0,0,0,0,0,0,0,0}, {0,0,3,6,0,0,0,0,0}, {0,7,0,0,9,0,2,0,0 }, 
    {0,5,0,0,0,7,0,0,0}, {0,0,0,0,4,5,7,0,0}, {0,0,0,1,0,0,0,3,0}, {0,0,1,0,0,0,0,6,8}, 
    {0,0,8,5,0,0,0,1,0}, {0,9,0,0,0,0,4,0,0} };
    void insert_row(int i, int j, int value)//进行行插入的函数,用来组成网格
    {
        pd_node temp_node_one, temp_node_two, temp_node_three,temp_node_four;
        int current_index;
        current_index = 81 * i + 9 * j + value-1;
        temp_node_one = (pd_node) malloc(sizeof(struct DLX_node));
        temp_node_two = (pd_node) malloc(sizeof(struct DLX_node));
        temp_node_three = (pd_node) malloc(sizeof(struct DLX_node));
        temp_node_four = (pd_node) malloc(sizeof(struct DLX_node));
        temp_node_one->right = temp_node_two;
        temp_node_two->right = temp_node_three;
        temp_node_three->right = temp_node_four;
        temp_node_four->right = temp_node_one;
        temp_node_one->left = temp_node_four;
        temp_node_two->left = temp_node_one;
        temp_node_three->left = temp_node_two;
        temp_node_four->left = temp_node_three;
        temp_node_one->is_head = 0;
        temp_node_two->is_head = 0;
        temp_node_three->is_head = 0;
        temp_node_four->is_head = 0;
        temp_node_one->down = p_head[i * 9 + value - 1 ];
        temp_node_one->up = temp_node_one->down->up;
        temp_node_one->up->down = temp_node_one;
        temp_node_one->down->up = temp_node_one;
        mutual_index[i * 9 + value - 1].cul_value += 1;
        temp_node_two->down = p_head[j * 9 + value - 1 + 81];
        temp_node_two->up = temp_node_two->down->up;
        temp_node_two->up->down = temp_node_two;
        temp_node_two->down->up = temp_node_two;
        mutual_index[j * 9 + value + 81 - 1].cul_value += 1;
        temp_node_three->down = p_head[162 + ((i / 3) * 3 + j/ 3) * 9 + value - 1];
        temp_node_three->up = temp_node_three->down->up;
        temp_node_three->up->down = temp_node_three;
        temp_node_three->down->up = temp_node_three;
        mutual_index[162 + ((i / 3) * 3 + j/ 3) * 9 + value - 1].cul_value+= 1;
        temp_node_four->down = p_head[243 + i * 9 + j];
        temp_node_four->up =temp_node_four->down->up;
        temp_node_four->up->down = temp_node_four;
        temp_node_four->down->up = temp_node_four;
        mutual_index[243 + i * 9 + j].cul_value += 1;
        temp_node_one->index = temp_node_two->index = temp_node_three->index=temp_node_four->index = current_index;
        row++;
    }
    void swap_heap(int index_one, int index_two)//交换在堆中的两个元素的值,及相关数据索引
    {
        int intermidate_one, intermidate_two;
        intermidate_one = mutual_index[index_one].cul_value;
        intermidate_two = mutual_index[index_one].position_index;
        mutual_index[index_one].cul_value = mutual_index[index_two].cul_value;
        mutual_index[index_one].position_index = mutual_index[index_two].position_index;
        mutual_index[index_two].cul_value = intermidate_one;
        mutual_index[index_two].position_index = intermidate_two;
        position_index[mutual_index[index_two].position_index] = index_two;
        position_index[mutual_index[index_one].position_index] = index_one;
    
    }
    void heap_initial()//初始化堆
    {
        int k, i = 0;
        int current_min;
        for (i = (current_heap_number-1)/2; i >= 0; i--)
        {
            k = i;
            while (2 * k + 1 <= current_heap_number)
            {
                current_min = mutual_index[k].cul_value;
                current_min = current_min < mutual_index[2 * k + 1].cul_value ? current_min : mutual_index[2 * k + 1].cul_value;
                if (2 * k + 2 <= current_heap_number)
                {
                    current_min = current_min < mutual_index[2 * k + 2].cul_value ? current_min : mutual_index[2 * k + 2].cul_value;
                }
                if (current_min == mutual_index[k].cul_value)
                {
                    break;
                }
                else
                {
                    if (current_min == mutual_index[2 * k + 1].cul_value)
                    {
                        swap_heap(k, 2 * k + 1);
                        k = 2 * k + 1;
                    }
                    else
                    {
                        swap_heap(k, 2 * k + 2);
                        k = 2 * k + 2;
                    }
                }
            }
        }
    }
    void creat_dlx_sudoku(int input_matrix[9][9])//利用矩阵来建立十字网格
    {
        int i, j,k;
        unsigned int row_position[9];
        unsigned int column_position[9];
        unsigned int small_position[9];
        unsigned int optional_value;
        pd_node temp_swap_node;
        for (i = 0; i < 324; i++)
        {
            mutual_index[i].cul_value = 0;
            mutual_index[i].position_index = i;
            position_index[i] = i;
        }
        for (i = 0; i < 9; i++)
        {
            row_position[i] = 0;
            column_position[i] = 0;
            small_position[i] = 0;
        }
        for (i = 0; i < 9; i++)
        {
            for (j = 0; j < 9; j++)
            {
                if (input_matrix[i][j] != 0)
                {
                    row_position[i] = row_position[i] | (shift_base >> (input_matrix[i][j]-1));
                    column_position[j] = column_position[j] | (shift_base >> (input_matrix[i][j]-1));
                    small_position[(i/3)*3 +j/3] = small_position[(i/3)*3 + j/3] | (shift_base >> (input_matrix[i][j]-1));
                }
            }
        }
        p_head = (pd_node*) malloc(324 * sizeof(struct DLX_node*));
        for (i = 0; i < 324; i++)
        {
            p_head[i] = (pd_node) malloc(sizeof(struct DLX_node));
            p_head[i]->up = p_head[i];
            p_head[i]->down = p_head[i];
            p_head[i]->is_head =1;
        }
        for (i = 0; i < 324; i++)
        {
            p_head[i]->right = p_head[(i + 1) % 324];
            p_head[i]->left = p_head[(i + 323) % 324];
        }
        temp_swap_node = (pd_node) malloc(sizeof(struct DLX_node));
        temp_swap_node->down = temp_swap_node->up = temp_swap_node;
        temp_swap_node->is_head = 1;
        temp_swap_node->left = p_head[323];
        temp_swap_node->right = p_head[0];
        p_head[323]->right = temp_swap_node;
        p_head[0]->left = temp_swap_node;
        head = temp_swap_node;
        for (i = 0; i < 9; i++)
        {
            for (j = 0; j < 9; j++)
            {
                if (input_matrix[i][j] != 0)
                {
                    insert_row(i, j, input_matrix[i][j]);
                }
                else
                {
                    optional_value = row_position[i] | column_position[j] | small_position[(i / 3) * 3 + j / 3];
                    optional_value = ~optional_value;
                    for (k = 0; k < 9; k++)
                    {
                        if (((shift_base >> k)&optional_value))
                        {
                            insert_row(i, j, k+1);
                        }
                        else
                        {
                            //do nothing
                        }
                    }
                }
            }
        }
        heap_initial();
    }
    
    void delete_minimal()//删除堆中最小的元素
    {
        int k;
        int current_min;
        if (current_heap_number != 0)
        {
            swap_heap(0, current_heap_number);//交换最高元素与最低元素
            current_heap_number--;//然后将堆的大小进行缩减
            k = 0;
            while (2 * k + 1 <= current_heap_number)//然后,下面便是一些维护性的工作,用来维护最小堆
            {
                current_min = mutual_index[k].cul_value;
                current_min = current_min < mutual_index[2 * k + 1].cul_value ? current_min : mutual_index[2 * k + 1].cul_value;
                if (2 * k + 2 <= current_heap_number)
                {
                    current_min = current_min < mutual_index[2 * k + 2].cul_value ? current_min : mutual_index[2 * k + 2].cul_value;
                }
                if (current_min == mutual_index[k].cul_value)
                {
                    return;
                }
                else
                {
                    if (current_min == mutual_index[2 * k + 1].cul_value)
                    {
                        swap_heap(k, 2 * k + 1);
                        k = 2 * k + 1;
                    }
                    else
                    {
                        swap_heap(k, 2 * k + 2);
                        k = 2 * k + 2;
                    }
                }
            }
        }
        else//如果只剩下一个元素,那就不需要进行交换,直接将堆元素的个数降低一
        {
            current_heap_number = -1;
        }
    
    }
    void heap_renew(int target_position, int new_value)//对于第target_position列,进行度数更新
    {
        int heap_target_position,k,current_min;
        heap_target_position = position_index[target_position];//这个是这一列在堆中所在的位置
        k = heap_target_position;
        if (new_value < mutual_index[k].cul_value)//如果值是减少的,就直接进行赋值,然后维护堆的性质
        {
            mutual_index[k].cul_value = new_value;
            while (k > 0 && (mutual_index[(k - 1) / 2].cul_value > mutual_index[k].cul_value))//维护堆
            {
                swap_heap((k - 1) / 2, k);
                k = (k - 1) / 2;
            }
            if (new_value == 0)//如果是赋值为0,则从堆中进行删除,因为我们每次操纵一个元素,所以最多会有一个元素为0,所以肯定是最小值。
            {
                delete_minimal();
            }
        }
        else//对于值增大的情况
        {
            mutual_index[k].cul_value = new_value;
            if (new_value == 1)//如果新的值是1,则把这个元素重新加入堆中
            {
                current_heap_number++;//扩大堆的范围,我们可以证明重新加入堆中的元素一定是排在堆的末尾,当然条件是删除与插入的顺序是对应相反的
                while (k > 0 && (mutual_index[(k - 1) / 2].cul_value > mutual_index[k].cul_value))//由于新的值是1,所以不可能比上一个数大
                {
                    swap_heap((k - 1) / 2, k);
                    k = (k - 1) / 2;
                }
            }
            else//如果不是1,说明已经在堆中,所以不需要扩大堆的范围,直接赋值之后进行维护堆结构就行
            {
                while (2 * k + 1 <= current_heap_number)
                {
                    current_min = mutual_index[k].cul_value;
                    current_min = current_min < mutual_index[2 * k + 1].cul_value ? current_min : mutual_index[2 * k + 1].cul_value;
                    if (2 * k + 2 <= current_heap_number)
                    {
                        current_min = current_min < mutual_index[2 * k + 2].cul_value ? current_min : mutual_index[2 * k + 2].cul_value;
                    }
                    if (current_min == mutual_index[k].cul_value)
                    {
                        break;
                    }
                    else
                    {
                        if (current_min == mutual_index[2 * k + 1].cul_value)
                        {
                            swap_heap(k, 2 * k + 1);
                            k = 2 * k + 1;
                        }
                        else
                        {
                            swap_heap(k, 2 * k + 2);
                            k = 2 * k + 2;
                        }
                    }
                }
            }
        }
    }
    void node_heap_decrease(pd_node current_node)//对于一个点进行她所在的行的删除,因为一行中一定有四个元素,所以有四列,我们对这四列的度数都进行减少1
    {
        int i, j, k;
        k = current_node->index % 9;
        j = (current_node->index / 9) % 9;
        i = (current_node->index / 81) % 9;
        heap_renew(i * 9 + k, mutual_index[position_index[i * 9 + k]].cul_value - 1);
        heap_renew(81 + j * 9 + k, mutual_index[position_index[81 + j * 9 + k]].cul_value - 1);
        heap_renew(162 + ((i / 3) * 3 + j / 3) * 9 + k, mutual_index[position_index[162 + ((i / 3) * 3 + j / 3) * 9+k]].cul_value - 1);
        heap_renew(243 + i * 9 + j, mutual_index[position_index[243 + i * 9 + j]].cul_value - 1);
    }
    void node_heap_increase(pd_node current_node)//增加与减少的顺序是刚好相反的
    {
        int i, j, k;
        k = current_node->index % 9;
        j = (current_node->index / 9) % 9;
        i = (current_node->index / 81) % 9;
        heap_renew(243 + i * 9 + j, mutual_index[position_index[243 + i * 9 + j]].cul_value +1);
        heap_renew(162 + ((i / 3) * 3 + j / 3) * 9 + k, mutual_index[position_index[162 + ((i / 3) * 3 + j / 3) * 9+k]].cul_value + 1);
        heap_renew(81 + j * 9 + k, mutual_index[position_index[81 + j * 9 + k]].cul_value + 1);
        heap_renew(i * 9 + k, mutual_index[position_index[i * 9 + k]].cul_value + 1);
    }
    void in_stack(pd_node target_to_stack)
    {
        pd_node temp_node_one, temp_node_two, temp_node_three,temp_node_four;
        temp_node_one = target_to_stack->left;//在删除的时候,从当前点的左边开始
        while (temp_node_one != target_to_stack)//从左进行遍历
        {
            temp_node_three = temp_node_one->down;//每遇到一个节点,就往下开始遍历
            while (temp_node_three != temp_node_one)
            {
                if (temp_node_three->is_head != 1)//如果遇到的点不是头部节点,则当前行摘除
                {
                    temp_node_four = temp_node_three->right;//在删除行的过程中,我们采取的是从右往左删
                    while (temp_node_four != temp_node_three)//从右往左的每一个节点,将他的上下关系摘除,注意第一个点是不能删除的,因为我们需要将他们连接起来。
                    {
                        temp_node_four->up->down = temp_node_four->down;
                        temp_node_four->down->up = temp_node_four->up;
                        temp_node_four = temp_node_four->right;
                    }
                    node_heap_decrease(temp_node_three);//对这一行所占据的三列进行降低度数操作,每一个降低一度
                }
                else//对于是头节点的情况,我们将头节点与两边摘下来,而且对于头节点,我们不需要进行度数操作
                {
                    temp_node_three->left->right = temp_node_three->right;
                    temp_node_three->right->left = temp_node_three->left;
                }
                temp_node_three = temp_node_three->down;//继续往下遍历
            }
            temp_node_one = temp_node_one->left;
        }
        temp_node_three = temp_node_one->down;//然后对与当前列相交的行的进行删除
        while (temp_node_three != temp_node_one)
        {
            if (temp_node_three->is_head != 1)
            {
                temp_node_four = temp_node_three->right;
                while (temp_node_four != temp_node_three)
                {
                    temp_node_four->up->down = temp_node_four->down;
                    temp_node_four->down->up = temp_node_four->up;
                    temp_node_four = temp_node_four->right;
                }
                node_heap_decrease(temp_node_three);
            }
            else
            {
                temp_node_three->left->right = temp_node_three->right;
                temp_node_three->right->left = temp_node_three->left;
            }
            temp_node_three = temp_node_three->down;
        }
        node_heap_decrease(target_to_stack);//最后对当前行进行删除
        stack[stack_index++] = target_to_stack;//然后才是入栈
        available_column -= 4;
    }
    void out_stack()//出栈的顺序与入栈的顺序是刚好对称相反的
    {
        pd_node temp_node_one, temp_node_two, temp_node_three, temp_node_four;
        pd_node target_node;
        available_column += 4;
        temp_node_one=target_node = stack[stack_index - 1];
        temp_node_three =temp_node_one->up;
        node_heap_increase(temp_node_one);
        while (temp_node_three != temp_node_one)//先考虑当前列
        {
            if (temp_node_three->is_head == 1)
            {
                temp_node_three->right->left = temp_node_three;
                temp_node_three->left->right = temp_node_three;
            }
            else
            {
                temp_node_four = temp_node_three->left;
                while (temp_node_four != temp_node_three)
                {
                    temp_node_four->up->down = temp_node_four;
                    temp_node_four->down->up = temp_node_four;
                    temp_node_four = temp_node_four->left;
                }
                node_heap_increase(temp_node_three);
            }
            temp_node_three = temp_node_three->up;
        }
        temp_node_one = target_node->right;
        while (temp_node_one != target_node)
        {
            temp_node_three = temp_node_one->up;
            while (temp_node_three != temp_node_one)
            {
                if (temp_node_three->is_head == 1)
                {
                    temp_node_three->right->left = temp_node_three;
                    temp_node_three->left->right = temp_node_three;
                }
                else
                {
                    temp_node_four = temp_node_three->left;
                    while (temp_node_four != temp_node_three)
                    {
                        temp_node_four->up->down = temp_node_four;
                        temp_node_four->down->up = temp_node_four;
                        temp_node_four = temp_node_four->left;
                    }
                    node_heap_increase(temp_node_three);
                }
                temp_node_three = temp_node_three->up;
            }
            temp_node_one = temp_node_one->right;
        }
        stack_index--;
    }
    void print_result()//打印出结果
    {
        int out[9][9] = { 0 };
        int i, j, k,current_index;
        int m, n;
        for (m = 0; m < stack_index; m++)
        {
            current_index = stack[m]->index;
            k = current_index % 9;
            current_index /= 9;
            j = current_index % 9;
            current_index /= 9;
            i = current_index;
            out[i][j] = k+1;
        }
        printf("***********************
    ");
        for (m = 0; m < 9; m++)
        {
            for (n = 0; n < 9; n++)
            {
                printf("%d ", out[m][n]|a[m][n]);
            }
            printf("
    ");
        }
    }
    int find_next()//用来找下一个可以入栈的元素,如果无法入栈或者已经找到了解,则返回并进行回溯操作
    {
        int target_position;
        pd_node temp_node_one;
        if (available_column == current_heap_number)
        {
            if (available_column == -1)
            {
                print_result();
                return 2;
            }
            else
            {
                target_position = mutual_index[0].position_index;
                temp_node_one = p_head[target_position];
                temp_node_one = temp_node_one->down;
                in_stack(temp_node_one);
                return 1;
            }
        }
        else
        {
            return 0;
        }
    }
    void seek_sudoku()
    {
        int find_result = 0;
        pd_node temp_node_one;
        while (1)
        {
            find_result = find_next();
            if (!find_result)//如果无法入栈且目前没有找到解,则出栈
            {
                temp_node_one = stack[stack_index - 1];
                out_stack();
                temp_node_one = temp_node_one->down;
                while ((temp_node_one->is_head))//如果当前元素是当前列头节点,则递归出栈
                {
                    if (stack_index == 0)//如果栈空,则所有的搜索空间已经搜索完全 返回
                    {
                        return;
                    }
                    else
                    {
                        temp_node_one = stack[stack_index - 1];
                        out_stack();
                        temp_node_one = temp_node_one->down;
                    }
                }
                in_stack(temp_node_one);//将所选元素入栈
            }
            else
            {
                if (find_result / 2)//如果已经找到结果,则返回,事实上我们可以更改这个逻辑来应对有多个解的情况,并把它全部打印
                {
                    return;
                }
            }
        }
    }
    int main()
    {
        clock_t clock_one,clock_two,clock_three;
        clock_one = clock();
        creat_dlx_sudoku(a);
        clock_two = clock();
        printf("%d mscond passed in creat_dlx_sudoku 
    ", clock_two - clock_one);
        seek_sudoku();
        clock_three = clock();
        printf("%d mscond passed in seek_sudoku
    ", clock_three - clock_two);
    
    }

    重点参考文章

    http://www.cnblogs.com/grenet/p/3145800.html 这篇文章讲的是跳舞链的基本介绍,不过遗漏了跳舞链的启发算法

    http://www.cnblogs.com/grenet/p/3163550.html 这篇文章讲的是跳舞链在解数独上的引用,那篇文章里面的实现是直接开大数组。

    而我这篇里面的实现是使用链表来实现真正的十字链,而且用堆来实现优先级,使得每次取最小元素的时候的复杂度减少,所带来的副作用就是代码行数很大。

     

    ---恢复内容结束---

  • 相关阅读:
    JSP动作--JSP有三种凝视方式
    osgi实战学习之路:5.生命周期及利用命令、装饰者模式实现基于socket交互Bundle命令demo
    一个int类型究竟占多少个字节
    FORM验证简单demo
    centOS设为文本启动方式
    定时关机命令——shutdown
    【剑指offer】Q38:数字在数组中出现的次数
    Union和Union All的差别
    基于协同过滤的推荐引擎
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3378648.html
Copyright © 2020-2023  润新知