分治與遞歸——循環賽日程表

參考下~~~

問題描述:有n個運動員進行循環賽,要求設計滿足一下要求的日程表

1、  每兩人必須比賽一次且只比賽一次

2、  每個選手每天只能比賽一次

3、  要求比賽時間儘可能短(即n爲偶數時比賽n-1天,n爲奇數時比賽n天)

一、分治法

算法思想,先算n/2的日程表,然後將循環賽日程表左上覆制到右下,左下複製到右上,得到n的日程表,遞歸實現

實現代碼:

//循環賽日程表

#include <stdio.h>

#define N 1000

int a[N][N];

int b[N];

inline bool odd(int n)

{

    return n & 1;

}

void copy(int n)//將左上角抄到右下角,將右上角加n/2後抄到左下角,將左下角抄到右上角

{

    int m=n/2;

    int i,j;

    for(i=1;i<=m;++i)

        for(j=1;j<=m;++j)

        {

            a[i][j+m]=a[i][j]+m;//將左上角抄到右下角

            a[i+m][j]=a[i][j+m];//將右上角加n/2後抄到左下角

            a[i+m][j+m]=a[i][j];//將左下角抄到右上角

        }

}

void copyodd(int n)//n/2爲奇數時的複製,讓輪空選手與下一個爲參賽選手進行比賽

{

    int m=n/2;

    int i,j;

    for(i=1;i<=m;++i)

    {

        b[i]=m+i;

        b[m+i]=b[i];

    }

    for(i=1;i<=m;++i)

    {

        for(j=1;j<=m+1;++j)

        {

            if(a[i][j]>m)

            {

                a[i][j]=b[i];

                a[m+i][j]=(b[i]+m)%n;

            }

            else

                a[m+i][j]=a[i][j]+m;

        }

        for(j=2;j<=m;++j)

        {

            a[i][m+j]=b[i+j-1];

            a[b[i+j-1]][m+j]=i;

        }

    }

}

void makecopy(int n)

{

    if(n/2>1 && odd(n/2)) copyodd(n);

    else copy(n);

}

void tour(int n)

{

    if(n==1)

    {

        a[1][1]=1;

        return;

    }

    if(odd(n))

    {

        tour(n+1);//n爲奇數,就設置一個虛擬的n+1,然後就有偶數個人了。。。。和一休的那個分馬很像啊

        return;

    }

    tour(n/2);

    makecopy(n);

}

void out(int n)

{

if(n==1)

    {

        printf("1n");

        return;

    }

    int i,j;

    int m;

    if(odd(n))

        m=n+1;

    else

        m=n;

    for(i=1;i<=n;++i)

    {

        for(j=1;j<=m;++j)

        {

            if(a[i][j]>n)//當比賽日程是與那位虛擬出來的n+1號選手比賽時,輸出0,代表輪空

                printf("0 ");

            else

                printf("%d ",a[i][j]);

        }

        printf("n");

    }

}

int main()

{

    int n;

    while(scanf("%d",&n),n)

    {

        tour(n);

        out(n);

    }

    return 0;

}

2、多邊形法(我的實現),通過旋轉多邊形的一種巧妙方法

//循環賽日程表

#include <stdio.h>

#define N 1000

int a[N][N];

inline bool odd(int n)

{

    return n & 1;

}

void init()

{

    int i;

    for(i=0;i<N;++i)

        a[i][0]=i;

}

void tour(int n)

{

    if(odd(n))

        tour(n+1);

    else

    {

        int i,j,k;

        int m=n-1;

        int p,q;

        for(i=1;i<=m;++i)//第一天到第n-1

        {

            j=i;

            p=j+1;

            if(p>m) p=p-m;

            a[p][i]=n;

            a[n][i]=p;

            for(k=0;k<=n/2-2;++k)

            {

                q=j-k;

                p=j+k+2;

                if(p>m) p-=m;

                if(q<=0) q+=m;

                a[q][i]=p;

                a[p][i]=q;

            }

        }

    }

}

void out(int n)

{

       if(n==1)

    {

        printf("1n");

        return;

    }

    int i,j;

    int m;

    if(odd(n))

        m=n+1;

    else

        m=n;

    for(i=1;i<=n;++i)

    {

        for(j=0;j<m;++j)

        {

            if(a[i][j]>n)

                printf("0 ");

            else

                printf("%d ",a[i][j]);

        }

        printf("n");

    }

}

int main()

{

    int n;

    init();

    while(scanf("%d",&n),n)

    {

        tour(n);

        out(n);

    }

    return 0;

}

4、  多邊形法(王曉東算法設計與分析教材上的實現,比較費解,比較牛逼)

#include <stdio.h>

#define N 1000

int a[N][N];

int b[N];

inline bool odd(int n)

{

    return n & 1;

}

void init()

{

    int i;

    for(i=0;i<N;++i)

        a[i][0]=i;

}

void tour(int n)

{

    a[n][1]=n;

    if(n==1) return;

    int m=odd(n) ? n : n-1;

    int i,j,k,r;

    for(i=1;i<=m;++i)

    {

        a[i][1]=i;

        b[i]=i+1;

        b[m+i]=i+1;

    }

    for(i=1;i<=m;++i)

    {

        a[1][i+1]=b[i];

        a[b[i]][i+1]=1;

        for(j=1;j<=m/2;++j)

        {

            k=b[i+j];

            r=b[i+m-j];

            a[k][i+1]=r;

            a[r][i+1]=k;

        }

    }

}

void out(int n)

{

    if(n==1)

    {

        printf("1n");

        return;

    }

    int i,j;

    int m;

    if(odd(n))

        m=n+1;

    else

        m=n;

    for(i=1;i<=n;++i)

    {

        for(j=1;j<=m;++j)

        {

            if(a[i][j]>n)

                printf("0 ");

            else

                printf("%d ",a[i][j]);

        }

        printf("n");

    }

}

int main()

{

    int n;

    init();

    while(scanf("%d",&n),n)

    {

        tour(n);

        out(n);

    }

    return 0;

}

發佈了36 篇原創文章 · 獲贊 65 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章