• 第一周 搜索与回溯算法,贪心算法


    先放上算法框架:

    递归回溯法算法框架[一]

    int Search(int k)

     {

     for (i=1;i<=算符种数;i++)

      if (满足条件)

         {

        保存结果

        if (到目的地) 输出解;

                  else Search(k+1);

        恢复:保存结果之前的状态{回溯一步}

         }

     }

    递归回溯法算法框架[二]

    int Search(int k)

     {

       if  (到目的地) 输出解;

       else

        for (i=1;i<=算符种数;i++)

         if  (满足条件)

           {

            保存结果;

                         Search(k+1);

            恢复:保存结果之前的状态{回溯一步}

           }

     }

    例题:

    【例1】素数环:从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

    【算法分析】

    非常明显,这是一道回溯的题目。从1开始,每个空位有20种可能(即所谓的算符种数),只要填进去的数合法:与前面的数不相同;与左边相邻的数的和是一个素数(即满足的条件)。第20个数(即目的地)还要判断和第1个数的和是否素数(可以放在输出里做)

    【例3】任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。当n=7共14种拆分方法

    #include<cstdio>

    #include<iostream>

    #include<cstdlib>

    using namespace std;

    int a[10001]={1},n,total;

    int search(int,int);

    int print(int);

    int main()

    {

        cin>>n;

        search(n,1);                            

     //将要拆分的数n传递给s

        cout<<"total="<<total<<endl;              //输出拆分的方案数

        system("pause");

    }

    int search(int s,int t)

    {

        int i;

        for (i=a[t-1];i<=s;i++)

         if (i<n)

    //当前数i要大于等于前1位数,且不过n

          {

           a[t]=i;

    //保存当前拆分的数i

           s-=i;           

    //s减去数i, s的值将继续拆分

           if (s==0) print(t);                   

    //当s=0时,拆分结束输出结果

             else search(s,t+1);                 

    //当s>0时,继续递归

           s+=i;                                 

    //回溯:加上拆分的数,以便产分所有可能的拆分

          }

    }

    int print(int t)

    {

        cout<<n<<"=";

        for (int i=1;i<=t-1;i++)                     

    //输出一种拆分方案

          cout<<a[i]<<"+";

        cout<<a[t]<<endl;

        total++;                                 

    //方案数累加1

    }

    【例4】八皇后问题:要在国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃。(提示:皇后能吃同一行、同一列、同一对角线的任意棋子。)

    放置第i个(行)皇后的算法为:

    int search(i);

     {

        int j;

       for (第i个皇后的位置j=1;j<=8;j++ )      //在本行的8列中去试

       if (本行本列允许放置皇后)

        {

         放置第i个皇后;

              对放置皇后的位置进行标记;

         if (i==8) 输出                                //已经放完个皇后

            else search(i+1);                //放置第i+1个皇后

         对放置皇后的位置释放标记,尝试下一个位置是否可行;

        }

     }

    【算法分析】

            显然问题的关键在于如何判定某个皇后所在的行、列、斜线上是否有别的皇后;可以从矩阵的特点上找到规律,如果在同一行,则行号相同;如果在同一列上,则列号相同;如果同在/ 斜线上的行列值之和相同;如果同在\ 斜线上的行列值之差相同;从下图可验证: 

    考虑每行有且仅有一个皇后,设一维数组A[1..8]表示皇后的放置:第i行皇后放在第j列,用A[i]=j来表示,即下标是行数,内容是列数。例如:A[3]=5就表示第3个皇后在第3行第5列上。

    经过对例题和上机练习的研究,我发现这就是传说中的:暴搜。。。

    值得一提的是排列除了一个一个放的另一种方法:

    先读入整个序列,对于这个序列,要做的就是确定第一个放什么,轮流拿这个序列中的每个元素放进来,然后再对除了第一个以外的序列执行同样操作。

    如果有重复元素,在放每一个元素之前,要判断与这个元素相同的元素之前有没有用过。放代码(允许重复元素):

     #include <iostream>
     #include <algorithm>
     #include <cstdio>
     using namespace std ;
     long long ans;
     int ok(char str[],int a ,int b )
     {
              if(b>a)
               for(int i=a;i<b;i++)
                  if(str[i]==str[b])
                      return 0;
               return 1;
     }
     void perm(char str[],int k,int m)
     {
               int i;
               if(k==m)
               {
                  ans++;
                  for(i=0;i<=m;i++)
                      printf("%c",str[i]);
                  printf(" ");
                  return ;
               }
               else for(i=k;i<=m;i++)
                       if(ok(str,k,i))
                       {
                               swap(str[k],str[i]);
                               perm(str,k+1,m);
                               swap(str[k],str[i]);
                       }
       
     }
     int main()
     {
          char str[505];
          int n,i;
          scanf("%d",&n);
          getchar();
          ans=0;
          for(i=0;i<n;i++)
              scanf("%c",&str[i]);
          perm(str,0,n-1) ;
          printf("%lld ",ans);
          return 0;
     }
    贪心算法
    若在求解一个问题时,能根据每次所得到的局部最优解,推导出全局最优或最优目标。那么,我们可以根据这个策略,每次得到局部最优解答,逐步而推导出问题,这种策略称为贪心法。
  • 相关阅读:
    单例模式学习(一)
    java线程池学习(一)
    redis面试总结(二)
    redis面试总结(一)
    spark 内存溢出处理
    大数据面试总结(一)
    Spark 知识点总结--调优(一)
    组合数据类型
    一些小细节
    文件归档
  • 原文地址:https://www.cnblogs.com/zkx06111/p/3659693.html
Copyright © 2020-2023  润新知