zoukankan      html  css  js  c++  java
  • 算法分析与设计实验三 回溯法 24点问题 n皇后问题

    实验目的
    学习编程实现深度优先搜索状态空间树求解实际问题的方法, 着重体会求解第一个可行解和求解所有可行解之间的差别。 加深理解回溯法通过搜索状态空间树、同时用约束函数剪去不含答案状态子树的算法思想, 会用蒙特卡罗方法估计算法实际生成的状态空间树的结点
    数。

    实验内容
    1、 求 24 点问题
    给定四个 1-9 之间的自然数, 其中每个数字只能使用一次,用算术运算符+,-,*,/构造出一个表达式,将这 4 个正整数连接起来(可以使用括号),使最终的得数为 24。 要求根据问题的特征设计具体算法并编程实现, 输入数据为 4 个自然数。输出若有多个满足要求的表达式, 则只输出其中一组; 若搜索失败, 则输出“ Fail!”。
    【示例】 采用一个表达式中用括号确定运算先后次序的方式,如:
    输入 1, 5, 5, 5 四个自然数,输出((5-(1/5))*5)。
    输入 3, 3, 8, 8 四个自然数,输出(8/(3-(8/3)))。
    【测试数据】
    (1) 1,5,5,5 (2) 3,3,8,8 (3) 3,8,8,8 (4) 1,2,3,4 (5) 2,4,5,6
    (6) 4,2,2,5 (7) 1,2,2,6 (8) 4,2,8,8 (9) 0,3,8,8
    2、 n 皇后问题
    要求用回溯法求解 8-皇后问题, 使放置在 8*8 棋盘上的 8 个皇后彼此不受攻击, 即:任何两个皇后都不在同一行、 同一列或同一斜线上。 请输出 8 皇后问题的所有可行解。

    24点程序:

    /*   Function : 求解24点问题,回溯,dfs。
     *   Name     : 24点.cpp
     *   Author   : wyh7280
     *   Time     : 2015.05.20 17:15:00.000
     *   Update   : 2015.05.25 12:10:00.000
     */
    #include <iostream>
    #include <string>
    #include <cmath>
    #include <cstdlib>
    #include <cstdio>
    #include <ctype.h>
    using namespace std;
    //宏定义
    const double PRECISION = 1E-6; //精度常量
    const int COUNT_OF_NUMBER = 4; //算24点的自然数个数
    const int NUMBER_TO_BE_CAL = 24;
    
    bool flag=false;
    int cnt=0; //标记解的数量,为1时退出
    
    class RationalNumber  //定义有理数类(分子、分母)
    {
    protected:
       int numerator,denominator; //numerator:分子,denominator:分母
       bool inf;
    protected:
       int gcd(int a,int b) //求最大公约数,辗转相除法
       {
          int temp;
          if(a<b)
          {
             temp=a;
             a=b;
             b=temp;
          }
          while(temp=a%b)
          {
             a=b;
             b=temp;
          }
          return b;
       }
    public:
       RationalNumber()  //constructor
       {
          inf=false;
       }
       RationalNumber(int n)
       {
          numerator=n;
          denominator=1;
          inf=false;
       }
       RationalNumber(int numerator,int denominator)
       {
          this->numerator=numerator;
          this->denominator=denominator;
          Simplify();
       }
       virtual ~RationalNumber() {}
       void Simplify()
       {
          if(denominator==1)
          {
             inf=false;
          }
          else if(numerator==0)
          {
             denominator=1;
             inf=false;
          }
          else
          {
             int k=gcd(abs(numerator),abs(denominator));
             numerator/=k;
             denominator/=k;
             if(denominator==1)
                inf=false;
             else
                inf=true;
          }
        }
        //重载运算符
        RationalNumber operator+(const RationalNumber& b) const
        {
            RationalNumber result;
            result.denominator=this->denominator*b.denominator;
            result.numerator=this->numerator*b.denominator+this->denominator*b.numerator;
            result.Simplify();
            return result;
        }
        RationalNumber operator-(const RationalNumber& b) const
        {
            RationalNumber result;
            result.denominator=this->denominator*b.denominator;
            result.numerator=this->numerator*b.denominator-this->denominator*b.numerator;
            result.Simplify();
            return result;
        }
        RationalNumber operator*(const RationalNumber& b) const
        {
            RationalNumber result;
            result.denominator=this->denominator*b.denominator;
            result.numerator=this->numerator*b.numerator;
            result.Simplify();
            return result;
        }
        RationalNumber operator/(const RationalNumber& b) const
        {
            RationalNumber result;
            result.denominator=this->denominator*b.numerator;
            result.numerator=this->numerator*b.denominator;
            result.Simplify();
            return result;
        }
        RationalNumber& operator=(const RationalNumber& b)
        {
            denominator=b.denominator;
            numerator=b.numerator;
            return (*this);
        }
        RationalNumber& operator=(int b)
        {
            denominator=1;
            numerator=b;
            return (*this);
        }
        int Numerator() const
        {
            return numerator;
        }
        int Denominator() const
        {
            return denominator;
        }
        string strshow()
        {
            string str;
            char buffer[20];
            itoa(numerator,buffer,10);
            str=buffer;
            if(denominator!=1)
            {
                itoa(denominator,buffer,10);
                str=str+"/"+buffer;
            }
            return str;
        }
    };
    
    RationalNumber number[COUNT_OF_NUMBER];  //用数组number[]保存操作数
    string expression[COUNT_OF_NUMBER];      //用数组expression[]保存算式
    
    bool Search(int n) //递归函数负责寻找可行解,其中 n 为本层调用的操作数个数。 每次两
                       //数运算后,原来的两个操作数被去除,运算结果成为新的操作数,因此总的操作数数量减 1。
    {
        if (n==1)
        {
           if (fabs(number[0].Numerator ()*1.0/number[0].Denominator ()-NUMBER_TO_BE_CAL)<PRECISION&&cnt==0)
           {
                cout<<"Output one avaiable solution: "<<expression[0]<<endl; //输出表达式
                flag=true;
                cnt=1;
                return true;
            }
           else
           {
                // flag=false;
                return false;
           }
        }
        int i,j,k;
        RationalNumber temp;
        for ( i=0;i<n;i++)
        {
            if(n==4){
            temp=number[i]-number[i+1];
            if(temp.Numerator ()==0)
            continue;
        }
        for (j=i+1;j<n;j++)
        {
            if(n==4)
            {
                for(k=i+1;k<j;k++)
                {
                    temp=number[j]-number[k];
                    if(temp.Numerator ()==0)
                    break;
                }
            if(k<j)
                continue;
       }
       RationalNumber a, b;
       string expa, expb;
       a=number[i]; //用a保存number[i]
       b=number[j]; //用b保存number[j]
       number[j]=number[n-1]; //将number[n-1]向前填入到原来number[j]的位置
       expa=expression[i]; //用expa保存expression[i]
       expb=expression[j]; //用expb保存expression[j]
       expression[j]=expression[n-1];
       //将expression[n-1]向前填入到原来expression[j]的位置
       //因为下一层递归调用search(n-1)将仅对下标为0~n-2的数进行操作了
       //加法
       expression[i]='('+expa+'+'+expb+')';
       //将a和b计算的算式填入到原来expression[i]的位置
       number[i]=a+b; //将a和b计算的结果填入到原来number[i]的位置
      // Search(n-1);
       if (Search(n-1)&&n!=4) //
       {
        number[i]=a;
       number[j]=b;
       expression[i]=expa;
       expression[j]=expb;
        return true;}
       //一旦得到一个可行解,即层层向上返回,从而确保只输出一个可行解
       //减法有两种情况a-b和b-a
       expression[i]='('+expa+'-'+expb+')';
       number[i]=a-b;
       if(number[i].Numerator ()>=0)
       {
      //  Search(n-1);
          if(Search(n-1)&&n!=4)
          {
             number[i]=a;
             number[j]=b;
             expression[i]=expa;
             expression[j]=expb;
             return true;
          }
       }
    
       expression[i]='('+expb+'-'+expa+')';
       number[i]=b-a;
       if(number[i].Numerator() >=0)
       {
           //  Search(n-1);
          if(Search(n-1)&&n!=4)
          {
             number[i]=a;
             number[j]=b;
             expression[i]=expa;
             expression[j]=expb;
             return true;
          }
       }
       //乘法
       expression[i]='('+expa+'*'+expb+')';
       number[i]=a*b;
      // Search(n-1);
       if(Search(n-1)&&n!=4)
       {
           number[i]=a;
           number[j]=b;
           expression[i]=expa;
           expression[j]=expb;
           return true;
        }
       //除法也有两种情况a/b和b/a
       if(b.Numerator()!=0)
       {
           expression[i]='('+expa+'/'+expb+')';
           number[i]=a/b;
        // Search(n-1);
          if(Search(n-1)&&n!=4)
          {
            number[i]=a;
            number[j]=b;
            expression[i]=expa;
            expression[j]=expb;
            return true;
          }
       }
       if(a.Numerator()!=0)
       {
          expression[i]='('+expb+'/'+expa+')';
          number[i]=b/a;
         // Search(n-1);
         if(Search(n-1)&&n!=4)
         {
           number[i]=a;
           number[j]=b;
           expression[i]=expa;
           expression[j]=expb;
           return true;
         }
       }
       //本轮调用完毕后,用a,b,expa,expb将数组number[]和expression[]恢复原状
        number[i]=a;
        number[j]=b;
        expression[i]=expa;
        expression[j]=expb;
       }
      }
      return false;
    }
    
    int main()
    {
        int x;
        cout<<"Please input four integers:";
        flag=false;
        for(int i=0;i<COUNT_OF_NUMBER;i++)
        {
            char buffer[20]; //分配长度为20的字符数组buffer[]
            cin>>x;
            number[i]=x;
            itoa(x,buffer,10); //itoa():将一个10进制的integer数转换为string类型
            //即:把输入的int型操作数x,转变成可以放在buffer[]中的string类型
            expression[i]=buffer; //用expression[i]指针指向buffer[]数组空间的起始位置
        }
        Search(4);
        if(flag==false)
        cout<<"Fail
    ";
     return 0;
    }

    n皇后程序(主函数调用实现8皇后求解)

    /*   Function : 求解 n-皇后问题,本题求解8皇后(可自行修改n值),用回溯法深度优先遍历状态空间树, 并利用约束函数进行剪枝。
     *   Name     : 8皇后问题.cpp
     *   Author   : wyh7280
     *   Time     : 2015.05.26 12:01:00.000
     *   Update   : no
     */
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <math.h>
    using namespace std;
    
    bool Place(int k,int i,int *x);
    void NQueens(int k,int n,int *x);;
    void NQueens(int n,int *x);
    
    int main()
    {
        int x[8];
        for(int i=0;i<8;i++) x[i]=-1;
        NQueens(8,x);
    }
    
    bool Place(int k,int i,int *x) //判定两个皇后是否在同一列或在同一斜线上
    {
       for (int j=0;j<k;j++)
       if ((x[j]==i)||(abs(x[j] -i)==abs(j-k))) return false;
       return true;
    }
    void NQueens(int k,int n,int *x) //递归函数(求解n皇后问题)
    {
        for (int i=0;i<n;i++)
        {
            if(Place(k,i,x))
            {
                x[k]=i;
                if (k==n-1)    //输出所有可行解
                {
                    for (i=0;i<n;i++) cout<<x[i]<<" ";
                    cout<<endl;
                }
                else
                {
                   NQueens(k+1,n,x);
                }
           }
        }
    }
    void NQueens(int n,int *x)
    {
         NQueens(0,n,x);
    }
    


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    border-radius
    border-style
    border-width
    border
    max-width
    min-width
    clip 语法
    left
    z-index
    position
  • 原文地址:https://www.cnblogs.com/Tobyuyu/p/4965327.html
Copyright © 2011-2022 走看看