程序員面試寶典---8.3 打靶

程序員面試寶典---8.3 打靶

關鍵詞程序員面試寶典                                          

 

面試例題1一個射擊運動員打靶,靶一共有10環,連開10槍打中90環的可能性有多少種?請用遞歸算法編程實現。[中國某著名通信企業H面試題]

 

解析:靶上一共有10種可能——1環到10環,還有可能脫靶,那就是0環,加在一起共11種可能。這是一道考循環和遞歸的面試題。我們在這個程序中將利用遞歸的辦法實現打靶所有可能的演示,並計算出結果。讀者會問,難道一定要使用遞歸?當然不是。我們也可以連續用10個循環語句來表示程序,代碼如下:

 

for (i1=0;i1<=10;i1++)

 

  {

 

      for (i2=0;i2<=10;i2++)

 

      {

 

          for (i3=0;i3<=10;i3++)

 

          {

 

              ......

 

                for (i10=0;i10<=10;i10++)

 

                  {

 

                      if(i1+i2+i3+...+i10=90)

 

                      Print();

 

                  }

 

              ......

 

          }

 

      }

 

  }

 

但是,上面的循環程序雖然解決了問題,但時間複雜度和空間複雜度無疑是很高的。比較好的辦法當然是採用遞歸的方式,事實上公司也就是這麼設計的。遞歸的條件由以下4步完成:

 

1)如果出現這種情況,即便後面每槍都打10環也無法打夠總環數90,在這種情況下就不用再打了,則退出遞歸。代碼如下:

 

if(score < 0 || score > (num+1)*10 )  //次數num09

 

         {

 

              return;

 

         }

 

2)如果滿足條件且打到最後一次(因爲必須打10次),代碼如下:

 

    if(num == 0) 

 

     {

 

         store2[num] = score;

 

         Output( store2);

 

         return;

 

        

     }

 

3)如果沒有出現以上兩種情況則執行遞歸,代碼如下:

 

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

 

        {

 

            //這裏實際上爲了方便把順序倒了過來,store2[9]是第1

 

            //store2[8]是第2回……store2[0]是第10

 

            store2[num] = i;

 

            Cumput(score - i, num - 1,store2);

 

        }

 

4)打印函數,符合要求的則把它打印出來。代碼如下:

 

    public static void Output(int[] store2)

 

    {

 

       

 

        for(int i = 9; i>=0; --i)

 

        {

 

            Console.Write("   {0}",store2[i]);

 

           

 

        }

 

        Console.WriteLine();

 

        sum++;

 

               

 

    }

 

答案:

 

C#編寫的完整代碼如下:

 

using System ;

 

 

public class M

 

{

 

 

    //public static int[] store;

 

    //相當於設置了全局變量

 

    //這個全局變量sum是包含在M類中的

 

    public static int sum;

 

    public M()

 

    {

 

        int sum =0;

 

        //  int[] store =  {1,2,3,4,5,6,7,8,9,0};

 

       

 

    }

 

   

 

//打印函數

 

    //符合要求的則把它打印出來

 

    public static void Output(int[] store2)

 

    {

 

       

 

        for(int i = 9; i>=0; --i)

 

        {

 

            Console.Write("   {0}",store2[i]);

 

           

 

        }

 

        Console.WriteLine();

 

        sum++;

 

               

 

    }

 

   

 

    //計算總數,返回sum

 

    public static int sum2()

 

    {

 

        return sum;

 

    }

 

 

    public  static void Cumput(int score, int num, int[] store2 )

 

    {

 

       

 

        //如果總的成績超過了90環(也就是score<0),或者如果剩下要打靶

 

        //的成績大於10環乘以剩下要打的次數,也就是說即便後面的都打10

 

        //也無法打夠次數,則退出遞歸

 

        if(score < 0 || score > (num+1)*10 )  //次數num09

 

        {

 

            return;

 

        }

 

       

 

        //如果滿足條件且達到最後一層

 

        if(num == 0) 

 

        {

 

            store2[num] = score;

 

            Output( store2);

 

            return;

 

           

 

        }

 

       

 

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

 

        {

 

            store2[num] = i;

 

            Cumput(score - i, num - 1,store2);

 

        }

 

        //Console.Write("   {0}",store2[5]);

 

    }

 

}

 

 

public class myApp

 

{

 

    public static void Main( )

 

    {

 

        int[] store;

 

        store = new int[10];

 

        int sum = 0;

 

        //int a=90;

 

        //int b=9;

 

        //Output();

 

        M.Cumput(90,9,store);

 

        sum = M.sum2();

 

       

 

        //M.Cumput2(a,b,store);

 

        //Console.Write("   {0}",store[3]);

 

        //cout<<"總數:"<<sum<<endl;

 

        Console.Write(" 總數:   {0}",sum);

 

       

 

    }

 

}  

 

程序結果一共有92 378種可能。

 

也可以用C++編寫,代碼如下:

 

#include <iostream>

 

using namespace std;

 

int sum;

 

int store[10];

 

void Output()

 

{

 

    for(int i = 9; i>=0; --i)

 

    {

 

       cout<<store[i]<<" ";

 

    }

 

    cout<<endl;

 

    ++sum;

 

}

 

 

void Cumput(int score, int num)

 

{

 

   if(score < 0 || score > (num+1)*10 )  //次數num09

 

      return;

 

   if(num == 0) 

 

     {

 

        store[num] = score;

 

        Output();

 

        return;

 

     }

 

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

 

     {

 

        store[num] = i;

 

        Cumput(score - i, num - 1);

 

     }

 

}

 

 

int main(int argc, char* argv[])

 

    {

 

       Cumput(90, 9);

 

       cout<<"總數:"<<sum<<endl;

 

       return 0;

 

    }

 

面試例題2八皇后問題是一個古老而著名的問題,是回溯算法的典型例題。該問題是19世紀著名的數學家高斯1850年提出:在8×8格的國際象棋盤上擺放8個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。[英國某著名計算機圖形圖像公司面試題]

 

解析:遞歸實現n皇后問題。

 

算法分析:

 

數組abc分別用來標記衝突,a數組代表列衝突,從a[0]~a[7]代表第0列到第7列。如果某列上已經有皇后,則爲1,否則爲0

 

數組b代表主對角線衝突,爲b[i-j+7],即從b[0]~b[14]。如果某條主對角線上已經有皇后,則爲1,否則爲0

 

數組c代表從對角線衝突,爲c[i+j],即從c[0]~c[14]。如果某條從對角線上已經有皇后,則爲1,否則爲0

 

代碼如下:

#include <stdio.h>

 

 

static char Queen[8][8];

 

static int a[8];

 

static int b[15];

 

static int c[15];

 

static int iQueenNum=0; //記錄總的棋盤狀態數

 

 

void qu(int i);     //參數i代表行

 

 

int main()

 

{

 

  int iLine,iColumn;

 

 

  //棋盤初始化,空格爲*,放置皇后的地方爲@

 

  for(iLine=0;iLine<8;iLine++)

 

  {

 

    a[iLine]=0; //列標記初始化,表示無列衝突

 

    for(iColumn=0;iColumn<8;iColumn++)

 

      Queen[iLine][iColumn]='*';

 

  }

 

 

  //主、從對角線標記初始化,表示沒有衝突

 

  for(iLine=0;iLine<15;iLine++)

 

    b[iLine]=c[iLine]=0;

 

 

  qu(0);

 

  return 0;

 

}

 

 

void qu(int i)

 

{

 

  int iColumn;

 

 

  for(iColumn=0;iColumn<8;iColumn++)

 

  {

 

    if(a[iColumn]==0&&b[i-iColumn+7]==0&&c[i+iColumn]==0)

 

    //如果無衝突

 

    {

 

      Queen[i][iColumn]='@';  //放皇后

 

      a[iColumn]=1;           //標記,下一次該列上不能放皇后

 

      b[i-iColumn+7]=1;       //標記,下一次該主對角線上不能放皇后

 

      c[i+iColumn]=1;             //標記,下一次該從對角線上不能放皇后

 

      if(i<7) qu(i+1);        //如果行還沒有遍歷完,進入下一行

 

      else //否則輸出

 

      {

 

        //輸出棋盤狀態

 

        int iLine,iColumn;

 

        printf("%d種狀態爲:/n",++iQueenNum);

 

        for(iLine=0;iLine<8;iLine++)

 

        {

 

          for(iColumn=0;iColumn<8;iColumn++)

 

            printf("%c ",Queen[iLine][iColumn]);

 

          printf("/n");

 

        }

 

        printf("/n/n");

 

      }

 

 

      //如果前次的皇后放置導致後面的放置無論如何都不能滿足要求,則回溯,重置

 

      Queen[i][iColumn]='*';

 

      a[iColumn]=0;

 

      b[i-iColumn+7]=0;

 

      c[i+iColumn]=0;

 

    }

 

  }

 

}  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章