1. 程式人生 > >0008演算法筆記——【分治法】迴圈賽事日程表

0008演算法筆記——【分治法】迴圈賽事日程表

問題描述

     設有n=2^k個運動員要進行網球迴圈賽。現要設計一個滿足以下要求的比賽日程表:

(1)每個選手必須與其他n-1個選手各賽一次;
     (2)每個選手一天只能參賽一次;
     (3)迴圈賽在n-1天內結束。

     請按此要求將比賽日程表設計成有n行和n-1列的一個表。在表中的第i行,第j列處填入第i個選手在第j天所遇到的選手。其中1≤i≤n,1≤j≤n-1。8個選手的比賽日程表如下圖:


 演算法思路按分治策略,我們可以將所有的選手分為兩半,則n個選手的比賽日程表可以通過n/2個選手的比賽日程表來決定。遞迴地用這種一分為二的策略對選手進行劃分,直到只剩下兩個選手時,比賽日程表的制定就變得很簡單。這時只要讓這兩個選手進行比賽就可以了。如上圖,所列出的正方形表是8個選手的比賽日程表。其中左上角與左下角的兩小塊分別為選手1至選手4和選手5至選手8前3天的比賽日程。據此,將左上角小塊中的所有數字按其相對位置抄到右下角,又將左下角小塊中的所有數字按其相對位置抄到右上角,這樣我們就分別安排好了選手1至選手4和選手5至選手8在後4天的比賽日程。依此思想容易將這個比賽日程表推廣到具有任意多個選手的情形。

演算法步驟

     (1)用一個for迴圈輸出日程表的第一行 for(int i=1;i<=N;i++) a[1][i] = i

     (2)然後定義一個m值,m初始化為1,m用來控制每一次填充表格時i(i表示行)和j(j表示列)的起始填充位置。

     (3)用一個for迴圈將問題分成幾部分,對於k=3,n=8,將問題分成3大部分,第一部分為,根據已經填充的第一行,填寫第二行,第二部分為,根據已經填充好的第一部分,填寫第三四行,第三部分為,根據已經填充好的前四行,填寫最後四行。for (ints=1;s<=k;s++)  N/=2;

     (4)

用一個for迴圈對③中提到的每一部分進行劃分for(intt=1;t<=N;t++)對於第一部分,將其劃分為四個小的單元,即對第二行進行如下劃分


     同理,對第二部分(即三四行),劃分為兩部分,第三部分同理。

 (5)最後,根據以上for迴圈對整體的劃分和分治法的思想,進行每一個單元格的填充。填充原則是:對角線填充

     for(int i=m+1;i<=2*m;i++) //i控制行      

          for(int j=m+1;j<=2*m;j++)  //j控制列       

          { 

              a[i][j+(t-1)*m*2]= a[i-m][j+(t-1)*m*2-m];/*右下角的值等於左上角的值 */ 

              a[i][j+(t-1)*m*2-m] =a[i-m][j+(t-1)*m*2];/*左下角的值等於右上角的值 */

         } 

     執行過程

    (1)由初始化的第一行填充第二行

     

     (2)由s控制的第一部分填完。然後是s++,進行第二部分的填充

    

     (3)最後是第三部分的填充

     

程式清單

  1. //2d11 分治法,迴圈賽事日程表
  2. #include "stdafx.h"
  3. #include <iostream>    
  4. #include <math.h>
  5. usingnamespace std;   
  6. void Table(int k,int n,int **a);  
  7. void input(int &k);  
  8. void output(int **a,int n);  
  9. int main()  
  10. {  
  11.     int k;  
  12.     input(k);  
  13.     int n=1;  
  14.     //n=2k(k>=1)個選手參加比賽
  15.     for(int i=1; i<=k; i++)  
  16.         n *= 2;  
  17.     //根據n動態分配二維陣列a
  18.     int **a = newint *[n+1];  
  19.     for(int i=0;i<=n;i++)  
  20.     {  
  21.         a[i] = newint[n+1];  
  22.     }  
  23.     Table(k,n,a);  
  24.     cout<<"迴圈賽事日程表為:"<<endl;  
  25.     output(a,n);  
  26.     //釋放空間
  27.     for(int i=0;i<=n;i++)  
  28.     {  
  29.         delete[] a[i];  
  30.     }  
  31.     delete[] a;  
  32.     return 0;  
  33. }  
  34. void input(int &k)  
  35. {  
  36.     cout<<"請輸入k值:"<<endl;  
  37.     cin>>k;  
  38. }  
  39. void output(int **a,int n)  
  40. {  
  41.     for(int i=1; i<=n; i++)  
  42.     {  
  43.         for(int j=1; j<=n; j++)  
  44.         {  
  45.             cout<<a[i][j]<<" ";  
  46.         }  
  47.         cout<<endl;  
  48.     }  
  49. }  
  50. void Table(int k,int n,int **a)  
  51. {  
  52.     for(int i=1; i<=n; i++)  
  53.         a[1][i]=i;//設定日程表第一行
  54.     int m = 1;//每次填充時,起始填充位置
  55.     for(int s=1; s<=k; s++)  
  56.     {  
  57.         n /= 2;  
  58.         for(int t=1; t<=n; t++)  
  59.         {  
  60.             for(int i=m+1; i<=2*m; i++)//控制行
  61.             {  
  62.                 for(int j=m+1; j<=2*m; j++)//控制列
  63.                 {  
  64.                     a[i][j+(t-1)*m*2] = a[i-m][j+(t-1)*m*2-m];//右下角等於左上角的值
  65.                     a[i][j+(t-1)*m*2-m] = a[i-m][j+(t-1)*m*2];//左下角等於右上角的值
  66.                 }  
  67.             }  
  68.         }  
  69.         m *= 2;  
  70.     }  
  71. }  
程式執行結果: