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)
同理,對第二部分(即三四行),劃分為兩部分,第三部分同理。
(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)最後是第三部分的填充
程式清單:
- //2d11 分治法,迴圈賽事日程表
- #include "stdafx.h"
- #include <iostream>
- #include <math.h>
- usingnamespace std;
- void Table(int k,int n,int **a);
- void input(int &k);
- void output(int **a,int n);
- int main()
- {
- int k;
- input(k);
- int n=1;
- //n=2k(k>=1)個選手參加比賽
- for(int i=1; i<=k; i++)
- n *= 2;
- //根據n動態分配二維陣列a
- int **a = newint *[n+1];
- for(int i=0;i<=n;i++)
- {
- a[i] = newint[n+1];
- }
- Table(k,n,a);
- cout<<"迴圈賽事日程表為:"<<endl;
- output(a,n);
- //釋放空間
- for(int i=0;i<=n;i++)
- {
- delete[] a[i];
- }
- delete[] a;
- return 0;
- }
- void input(int &k)
- {
- cout<<"請輸入k值:"<<endl;
- cin>>k;
- }
- void output(int **a,int n)
- {
- for(int i=1; i<=n; i++)
- {
- for(int j=1; j<=n; j++)
- {
- cout<<a[i][j]<<" ";
- }
- cout<<endl;
- }
- }
- void Table(int k,int n,int **a)
- {
- for(int i=1; i<=n; i++)
- a[1][i]=i;//設定日程表第一行
- int m = 1;//每次填充時,起始填充位置
- for(int s=1; s<=k; s++)
- {
- n /= 2;
- for(int t=1; t<=n; t++)
- {
- for(int i=m+1; i<=2*m; i++)//控制行
- {
- for(int j=m+1; j<=2*m; 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];//左下角等於右上角的值
- }
- }
- }
- m *= 2;
- }
- }