10.  Търсене. Последователно и двоично търсене. Търсене с
      връщане
    
    Последователно търсене [4, стр. 231]
      
    ** Човешката дейност търсене
      
      ** Опростен модел на търсене
      
      ** Фундаментални операции над елемнтите на множество (правилна
      оценка на ефективността на алгоритмите за търсене)
      -- инициализиране
      -- търсене
      -- вмъкване
      -- изтриване
      -- обединяване на множества
      --  сортиране.
      
      ** Ключ, повтарящи се ключове
      -- има ли елемент с даден ключ? [bool exists(unsigned key)]
      -- индекс на елемент (обект) с даден ключ? [unsigned find_one(unsigned
        key)]
      -- брой елементи с даден ключ? [unsigned count(unsigned key)]
      -- индекси на всички елементи (обекти) с даден ключ? [vector<unsigned>
        find_all(unsigned key)]
      
      ** Последователно (линейно) търсене
      Проверяваме последователно елементите на множеството (което е
      линейно наредено), докато или намерим търсения елемент или стигнем
      до края на редицата. 
      Ефективност на алгоритъма за линейно търсене:
      Броят на обръщенията към елементите на масива зависи от търсеното
      число, но в най-лошия случай, когато числото не се среща в масива,
      е равен на дължината на масива. Следователно сложността на
      алгоритъма е O(n). 
    // lsearch.cpp 
        
    int
              linear_search(vector<int> v, int a)
        {
           int i;
           for (i = 0; i <
              v.size(); i++)
              
              if (v[i] == a) return i;
           return -1;
        } 
    ** Последователно търсене в сортиран списък с поддържане на
      сортирания списък при вмъкване на нов елемент.
      
      ** Последователно търсене с преподреждане
    
    Двоично търсене (разделай и владей) [4.3, стр. 239]
    // bsearch.cpp 
          
    int
              binary_search(vector<int> v, int from, int to, int
              a)
        {
           if (from >
              to)  return -1;
           int mid = (from + to)
              / 2;
           int diff = v[mid] - a;
           if (diff == 0) return
              mid;         
              /* v[mid] == a */
           else if (diff <
              0)                 
              /* v[mid] < a */
             
              return binary_search(v, mid + 1, to, a);
           else
             
              return binary_search(v, from, mid - 1, a);
        } 
    Търсене и сортиране на реални данни 
      // esearch.cpp 
    
    int
              binary_search(vector<Employee> v, int from, int to,
              string n)
        {
           if (from > to)
              return -1;
           int mid = (from + to)
              / 2;
           if (v[mid].get_name()
              == n)  return mid;
           else if
              (v[mid].get_name() < n)
             
              return binary_search(v, mid + 1, to, n);
           else
             
              return binary_search(v, from, mid - 1, n);
        }
            
    Търсене на корен на уравнение с произволна точност
             
    
    
    Tърсене с връщане
    
    Класификация на задачите [6.1]
    Сложност по време [6.1.1] 
    NP- задачи: Класът на полиномиално проверимите задачи
    P- задачи: Съществува решение с полиномиална сложност
    P = NP
      ???
    Експоненциални задачи: Съществува алгоритъм с експоненциална
    сложност
    Сложност по памет  [6.1.2] 
    Нерешими задачи  [6.1.3] 
    Задачи, за които съществува доказателство, че не могат да бъдат
    решени, независимо от това с колко време и памет разполагаме. 
    Примери [6.1.4] 
    Полиномиално решими задачи: търсене, сортиране, ...
    NP- задачи: Съществуване на делител на цяло положително число,
    по-малък от зададено число. 
    Класификация по памет: игра на шах
    Нерешими задачи: Дали дадена програма е в безкраен цикъл (Голямата
      теорема на Ферма).
    
    int main()
    {
        unsigned a,
      b , c, n, u;
        for (u =
      3;;)
        {
       
          for (a = 1; a < u; a++)
       
              for (b = 1; b < u; b++)
       
                  for (c=1;
      c < u; c++)
       
                 
          for (n=3; n < u; n++)
       
                 
              if (pow(a, n) + pow(b, n) ==
      pow(c, n)) exit(0);
       
          u++;
        }
        return 0;
    } 
    Неопределени задачи: Задача на Сколем - За дадена матрица дали
    съществува число n такова,
    че матрицата, повдигната на степен n съдържа нула в горния десен
    ъгъл.
    
    NP-пълни задачи [6.2] 
    (Wiki)
    
    Търсене с връщане [6.3]
    
    Разходка на коня [6.3.4]
    // knight.c
      #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXN 10
    
    #define MAXD 10
    
    const unsigned n = 6;
    
    const unsigned startX = 1;
    const unsigned startY = 1;
    
    const unsigned maxDiff = 8;
    const int diffX[MAXD] = { 1,
      1, -1, -1, 2, -2, 2, -2 };
    const int diffY[MAXD] = { 2,
      -2, 2, -2, 1, 1, -1, -1 };
    
    unsigned board[MAXN][MAXN];
    unsigned newX, newY;
    
    void printBoard(void)
    { unsigned i, j;
      for (i = n; i > 0;
      i--) {
        for (j = 0;
      j < n; j++) printf("%3u", board[i-1][j]);
       
      printf("\n");
      }
      exit(0); 
    }
    
    void nextMove(unsigned X,
      unsigned Y, unsigned i)
    { unsigned k;
      board[X][Y] = i;
      if (i == n * n) {
      printBoard(); return; }
      for (k = 0; k <
      maxDiff; k++) {
        newX = X +
      diffX[k]; newY = Y + diffY[k];
        if ((newX
      >= 0 && newX < n && newY >= 0 &&
      newY < n) && (0 == board[newX][newY]))
         
      nextMove(newX, newY, i + 1);
      }
      board[X][Y] = 0;
    }
    
    int main(void) {
      unsigned i, j;
      for (i = 0; i < n;
      i++)
        for (j = 0;
      j < n; j++) board[i][j] = 0;
      nextMove(startX-1,
      startY-1, 1);
      printf("No solution.
      \n");
      return 0;
    }
    
    Задача за осемте царици
    [6.3.5]
    // queens.c
    #include<stdio.h>
    #include<stdlib.h>
    
    #define MAXN 100
    
    const unsigned n = 13;
    
    unsigned col[MAXN] , RD[2*MAXN
      - 1],
            
      LD[2*MAXN], queens [MAXN];
    
    void printBoard()
    { unsigned i , j ;
      for (i = 0; i < n;
      i++) {
       
      printf("\n");
        for (j = 0;
      j < n; j++)
         
      if(queens[i] == j) printf("x ");
         
      else printf(". ");
      }
      printf("\n");
      exit(0);
    }
    
    void generate(unsigned i)
    { if(i == n) printBoard();
      unsigned
      k;    
      for (k = 0; k <= n;
      k++) {
        if (col[k]
      && RD[i + k] && LD[n + i - k]) {
         
      col[k] = 0; RD[i + k] = 0; LD[n + i - k] = 0; queens[i] = k;
         
      generate(i + 1);
         
      col[k] = 1; RD[i + k] = 1; LD[n + i - k] = 1;
        }
      }
    }
    
    int main(void) {
      unsigned i;
      for (i = 0; i < n;
      i++) col[i] = 1;
      for (i = 0; i < (2*n
      - 1); i++) RD[i] = 1;
      for (i = 0; i < 2*n;
      i++) LD[i] = 1;
      generate(0);
      printf("No
      solution!\n");
      return 0;
    }
    
    Метод на разклоненията и границите
    [6.4]
    Задача за търговския пътник
    Задача за раницата