“迴圈賽日程安排”問題的分而治之解決演算法

gudesheng發表於2008-01-03
/*
    標題:<<系統設計師>>應試程式設計例項-[分而治之演算法程式設計]
    作者:成曉旭
    時間:2002年09月15日(11:58:00-13:18:00)
          實現“裝箱”問題的貪婪演算法實現函式

*/

#include    
"stdio.h"
#include    
"stdlib.h"

//:====================“迴圈賽日程安排”問題的分而治之解決演算法====================
/*
    作者:成曉旭
    時間:2002年09月15日(11:58:38-20:00:00)
          完成“迴圈賽日程安排”問題的分而治之解決演算法
    ===================================================
    問題描述:
            設有n(n = 2^k)位選手參加網球迴圈賽,迴圈賽共進行n-1天,每位選手要與
        其他n-1位選手比賽一場,且每位選手每天必須比賽一場,不能輪空。試按此要求
        為比賽安排日程。

    程式設計思想:
            假設n位選手被順序編號為1,2,3,...,n,比賽的日程表是一個n行n-1列的表格,
        i行j列的表格內容是第i號選手在第j天的比賽對手。
            根據分而治之的原則,可從其中一半選手(2^(n-1位)的比賽日程,匯出全體n位
        選手的日程,最終細分到只有兩位選手的比賽日程出發。
            可假設只有8位選手參賽,若1至4號選手之間的比賽日程填在日程表的左上角
        (4行3列),5至8號選手之間的比賽日程填在日程表的左下角(4行3列);那麼左下角的
        內容可由左上角的對應項加上數字4得到。至此,剩餘的右上角(4行4列)是為編號小的
        1至4號選手與編號大的5至8號選手之間的比賽日程安排。例如,在第4天,讓1至4號選
        手分別與5至8號選手比賽,以後各天,依次由前一天的日程安排,讓5至8號選手“迴圈
        輪轉”即可。
        最後,比賽日程表的右下角的比賽日程表可由,右上角的對應項減去數字
        4得到。
    程式設計圖例:
        
    ===================================================================
    |*| 選手    1天        2天        3天        4天        5天        6天        7天    |*|
    ===================================================================
    |*|    1號    |    2    |    3    |    4    ||    5    |    6    |    7    |    8    |*|
    |*|    2號    |    1    |    4    |    3    ||    6    |    7    |    8    |    7    |*|
    |*|    3號    |    4    |    1    |    2    ||    7    |    8    |    5    |    6    |*|
    |*|    4號    |    3    |    2    |    1    ||    8    |    5    |    6    |    5    |*|
    ========[左上角]========================[右上角]===================
    |*|    5號    |    6    |    7    |    8    ||    1    |    4    |    3    |    2    |*|
    |*|    6號    |    5    |    8    |    7    ||    2    |    1    |    4    |    3    |*|
    |*|    7號    |    8    |    5    |    6    ||    3    |    2    |    1    |    4    |*|
    |*|    8號    |    7    |    6    |    5    ||    4    |    3    |    2    |    1    |*|
    ========[左下角]========================[右下角]===================
*/

#define    MAXN    64
//日程表陣列
int    calendar[MAXN + 1][MAXN];
void    Round_Robin_Calendar()
{
    
int i,j,m,number,p,q;
    printf(
"輸入選手個數:(注意:2^k) ");
    scanf(
"%d",&number);
    
//預置兩位選手的比賽日程表://第i位選手第j天與第calendar[i][j]位選手比賽
    calendar[1][1= 2;        //第1位選手第1天與第2位選手比賽
    calendar[2][1= 1;        //第2位選手第1天與第1位選手比賽
    m = 1;
    p 
= 1;
    
while(m < number)
    
{
        m 
++;
        
//p = p + p;
        p += p;
        q 
= 2 * p;    //為2^m位選手安排比賽日程
        
//填充日程表的左下角
        for(i = p + 1;i <= q;i++)
            
for(j = 1;j<= p - 1;j++)
                calendar[i][j] 
= calendar[i - p][j] + p;    //左下角的內容 = 左上角的對應項加上數字4[]
        
//填充日程表的右上角
        
//填充日程表的右上角的第1列
        calendar[1][p] = p + 1;        
        
for(i = 2;i <= p;i++)
            calendar[i][p] 
= calendar[i - 1][p] + 1;
        
//填充日程表的右上角的其他列,參照前一列填充當前列[迴圈輪轉演算法]
        for(j = p + 1;j < q;j++)
        
{
            
for(i = 1;i < p;i++)
                calendar[i][j] 
= calendar[i + 1][j - 1];
            calendar[p][j] 
= calendar[1][j - 1];
        }

        
//填充日程表的右下角
        for(j = p;j < q;j++)
            
for(i = 1;i <= p;i++)
                calendar[calendar[i][j]][j] 
= i;    //關鍵語句
        for(i = 1;i <= q;i++)
        
{
            
for(j = 1;j < q;j++)
                printf(
"%4d",calendar[i][j]);
            printf(
" ");
        }

        printf(
" ");
    }

}

//:====================“迴圈賽日程安排”問題的分而治之解決演算法====================

int main(int argc, char* argv[])
{
    Round_Robin_Calendar();
    printf(
" 應用程式執行結束! ");
    
return 0;
}




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=935878


相關文章