zoukankan      html  css  js  c++  java
  • 数独游戏 C++ 回溯法

    C++ 数独游戏(回溯)

    数独游戏的规则:

    1 每个数字在每一行只能出现一次

    2 每个数字在每一列只能出现一次

    3 每个数字在每一区只能出现一次

    下面的input.txt是一个例子的约束条件 第一列表示每一个数所在的行 第二列表示每一个数所在的列,第三个这个位置上的值。

    Input.txt

    1 1 7

    1 4 1

    1 8 8

    1 9 3

    2 1 4

    2 3 2

    2 5 7

    2 6 3

    3 4 4

    3 5 5

    3 8 2

    3 9 7

    4 3 7

    4 7 3

    4 8 1

    4 9 2

    5 2 4

    5 3 3

    5 4 8

    6 3 5

    6 5 9

    7 2 2

    7 3 1

    7 5 8

    8 2 3

    8 4 2

    8 6 1

    8 7 8

    9 7 2

    9 8 6

    9 9 1

    一  回溯法

    //============================================

    #include
    <iostream>

    #include
    <stdio.h>

    using namespace std;



    int State[9][9];

    ///------------------------------

    void InitState()

    {

    for (int i=0; i<9; i++)

    {

    for (int j=0; j<9;j++)

    {

    State[i][j]
    = 0;

    }

    }

    }



    //-------------------------------



    void Load()

    {

    freopen(
    "input.txt","r",stdin); //输入从input.txt

    int x, y, value;

    int temp = 0;

    while (scanf ("%d %d %d", &x, &y, &value) != EOF)

    {

    State[x
    -1][y-1] = value;

    }

    }



    //---------------------------------

    //检查每一个小区内只能出现一次

    bool ChechZone(int x, int y, int i)

    {

    int xZone = 3 * (x / 3); //找到每个小区的位置

    int yZone = 3 * (y / 3);



    int j = 0;

    int k = 0;

    bool flag = true;

    for (j=xZone; j<xZone+3; j++) //遍历小区的三行三列

    {

    for (k=yZone; k<yZone+3; k++)

    {

    //if (x == j && y == k)

    //{

    // continue;

    //}



    if ((x != j || y != k) && State[j][k] == i)

    {

    flag
    = false;

    goto A1;

    }

    }

    }

    A1:

    return flag;

    }



    //--------------------------------

    //检查是否符合条件

    bool ChechAssign(int x, int y, int i)

    {

    bool flag = true;

    for (int k=0; k<9; k++)

    {

    if (k != y && i == State[x][k] )

    {

    flag
    = false;

    }



    if (k != x && i == State[k][y] )

    {

    flag
    = false;

    }

    if (!ChechZone(x, y, i))

    {

    flag
    = false;

    }

    }

    return flag;

    }

    ///------------------------------

    int Search (int depth)

    {

    if (depth >= 81)

    {

    //return Chech();

    return 1;

    }



    int x, y;

    x
    = depth / 9 ;

    y
    = depth % 9 ;



    //检查x y有没有被 赋值

    if (0 != State[x][y])

    {

    return Search (depth + 1);

    }

    else //尝试赋值

    {

    for (int i=1; i<=9; i++)

    {

    //检查是否违反约束条件

    State[x][y]
    = i;

    if (ChechAssign(x, y, i))

    {

    if (Search(depth + 1))

    {

    return 1;

    }

    }

    State[x][y]
    = 0;

    }

    return 0;

    }

    }



    ///---------------------------------------

    void OutputState()

    {

    for (int i=0; i<9; i++)

    {

    for (int j=0; j<9; j++)

    {

    cout
    << State[i][j] << " ";

    if (0 == (j+1) % 3)

    {

    cout
    << " ";

    }

    }



    if (0 == (i + 1) % 3)

    {

    cout
    << endl;

    }

    cout
    << endl;

    }

    cout
    << endl;

    }







    //-------------------------------------

    int main ()

    {

    cout
    << "=======初始化========"<< endl << endl;

    InitState();

    //输入函数

    Load();

    OutputState();

    cout
    << "=======结果为======="<< endl << endl;

    //搜索

    if (Search(0))

    {

    OutputState();

    }

    else

    {

    //输出提示信息

    cout
    << "搜索失败!!!"<< endl;

    }

    cout
    << "===================="<< endl << endl;

    return 0;

    }

    二 优化后的回溯

    就是先排序后再回溯 排序的依据是:先算出第一个空格的所在行各所在列对他的约束的个数。然后从大到小进行排序。

    优化后的程序如下:

    #include <iostream>

    #include
    <stdio.h>

    using namespace std;



    // -------------------------------------------------------------------------



    int State[9][9];

    int StateSort[81][3]; //记录每个空元素的所在行列已有的数字个数 非空元素为0



    void Print()

    {

    for (int i=0; i<81; i++)

    {

    for (int j=0; j<3; j++)

    {

    cout
    << StateSort[i][j] << " ";

    }

    cout
    << endl;

    }

    }



    ///------------------------------

    void InitState()

    {

    int i, j;

    for (i=0; i<9; i++) //初始化State

    {

    for (j=0; j<9;j++)

    {

    State[i][j]
    = 0;

    }

    }



    for (i=0; i<81; i++) // 初始化StateSort

    {

    StateSort[i][
    0] = i / 9 + 1;

    StateSort[i][
    1] = i % 9 + 1;

    StateSort[i][
    2] = 0;

    }

    // Print();

    }



    //-------------------------------

    void Load()

    {

    freopen(
    "input.txt","r",stdin); //输入从input.txt

    int x, y, value;

    while (scanf ("%d %d %d", &x, &y, &value) != EOF)

    {

    State[x
    -1][y-1] = value;

    }

    }



    //---------------------------------

    void Count()// 算出每一个空元素的所在行和列约束的个数

    {

    int k;

    for (int i=0; i<9; i++)

    {

    for (int j=0; j<9; j++)

    {

    if (State[i][j] == 0)

    {

    int nCount = 0;

    for (k=0; k<9; k++)

    {

    if ( 0 != State[i][k])

    {

    nCount
    ++;

    }

    }

    for (k=0; k<9; k++)

    {

    if (0 != State[k][j])

    {

    nCount
    ++;

    }

    }

    StateSort[i
    *9+j][2] = nCount;

    }



    }

    }

    }



    //---------------------------------------------

    void Sort()

    {

    int pivotkey[3] ;

    for (int i=1; i<=81;i++)

    {

    if (StateSort[i][2] > StateSort[i-1][2])

    {

    pivotkey[
    2] = StateSort[i][2];

    pivotkey[
    1] = StateSort[i][1];

    pivotkey[
    0] = StateSort[i][0];



    for (int j=i-1; (pivotkey[2]>StateSort[j][2]) && (j>=0); --j)

    {

    StateSort[j
    +1][2] = StateSort[j][2];

    StateSort[j
    +1][1] = StateSort[j][1];

    StateSort[j
    +1][0] = StateSort[j][0];

    }

    StateSort[j
    +1][2] = pivotkey[2];

    StateSort[j
    +1][1] = pivotkey[1];

    StateSort[j
    +1][0] = pivotkey[0];

    }

    }

    //Print();

    }



    //---------------------------------

    //检查每一个小区内只能出现一次

    bool ChechZone(int x, int y, int i)

    {

    int xZone = 3 * (x / 3); //找到每个小区的位置

    int yZone = 3 * (y / 3);



    int j = 0;

    int k = 0;

    bool flag = true;

    for (j=xZone; j<xZone+3; j++) //遍历小区的三行三列

    {

    for (k=yZone; k<yZone+3; k++)

    {

    if ((x != j || y != k) && State[j][k] == i)

    {

    flag
    = false;

    goto A1;

    }

    }

    }

    A1:

    return flag;

    }



    //--------------------------------

    //检查是否符合条件

    bool ChechAssign(int x, int y, int i)

    {

    bool flag = true;

    for (int k=0; k<9; k++)

    {

    if (k != y && i == State[x][k] )

    {

    flag
    = false;

    }



    if (k != x && i == State[k][y] )

    {

    flag
    = false;

    }

    if (!ChechZone(x, y, i))

    {

    flag
    = false;

    }

    }

    return flag;

    }

    //-----------------------------------

    int DCount ()

    {

    int g_Count = 0;

    for (int i=0; i<81; i++)

    {

    if (0 != StateSort[i][2])

    {

    g_Count
    ++;

    }

    }

    return g_Count;

    }





    ///-------------------------------



    int Search (int depth)

    {

    if (depth >= DCount())

    {

    return 1;

    }



    int x, y;

    x
    = StateSort[depth][0] - 1;

    y
    = StateSort[depth][1] - 1;



    //检查x y有没有被 赋值

    if (0 != State[x][y])

    {

    return Search (depth + 1);

    }

    else //尝试赋值

    {

    for (int i=1; i<=9; i++)

    {

    State[x][y]
    = i;

    //检查是否违反约束条件

    if (ChechAssign(x, y, i))

    {

    if (Search(depth + 1))

    {

    return 1;

    }

    }

    State[x][y]
    = 0;

    }

    return 0;

    }

    }



    ///---------------------------------------

    void OutputState()

    {

    for (int i=0; i<9; i++)

    {

    for (int j=0; j<9; j++)

    {

    cout
    << State[i][j] << " ";

    if (0 == (j+1) % 3)

    {

    cout
    << " ";

    }

    }



    if (0 == (i + 1) % 3)

    {

    cout
    << endl;

    }

    cout
    << endl;

    }

    cout
    << endl;

    }



    //-------------------------------------

    int main ()

    {

    cout
    << "=======初始化========"<< endl << endl;

    InitState();

    //输入函数

    Load();

    OutputState();

    //计算每个元素所在行列已有的数字个数 非空元素为0

    Count();

    //Print();

    //cout <<"+++++++++"<<endl;

    //排序

    Sort();

    //Print();



    cout
    << "The Depth : " << DCount() << endl <<endl;

    cout
    << "=======结果为======="<< endl << endl;

    //搜索

    if (Search(0))

    {

    //输出

    OutputState();

    }

    else

    {

    //输出提示信息

    cout
    << "搜索失败!!!"<< endl;

    }

    cout
    << "===================="<< endl << endl;

    cout
    << DCount();

    return 0;

    }

    // -------------------------------------------------------------------------

    // $Log: $

    江西理工大学 Fangshenghui 2010-5-1

  • 相关阅读:
    大端与小端编号方法的区别
    socket、listen 等函数的打电话隐喻
    windows 网络编程报错 error LNK2019
    有符号数与无符号数之间的转换
    C++ 代码命名建议
    编写启发式代码的方法
    求给定数目的前 n 个素数
    不使用 “+” 实现加法操作
    二叉搜索树中两个节点的旋转
    Python玩转硬件:TPYBoard-Micropython开发板大盘点
  • 原文地址:https://www.cnblogs.com/fangshenghui/p/1725691.html
Copyright © 2011-2022 走看看