【算法作业】 循环赛问题 分治算法

来源:互联网 发布:java手机游戏培训 编辑:程序博客网 时间:2024/05/22 14:31

题目:

设有N个运动员要进行网球循环赛,设计一个满足以下要求的比赛日程表

1每个选手必须与其他n-1个选手各赛一次

2每个选手一天只能赛一次

3是偶数,循环赛进行n-1天,当n是奇数,循环赛进行n天。

 

思路分析:

如果n是奇数,其实就等于n+1种情况下将第n+1号选手轮空。所以只要考虑n是偶数的情况。用分治的思想来做,转换成n/2的子问题。考虑两种情况:


一、n/2为偶数。这种情况比较简单。例如n=4时。

        1 2 3 4

        2 1 4 3

        3 4 1 2

        4 3 2 1

可由n=2的子问题推出。

              1 2               1 2 3 4

              2 1               2 1 4 3

1 2         3 4               3 4 1 2

2 1  -->  4 3    -->      4 3 2 1

第一次变换下半部分=上半部分+n/2,第二次沿对角线对称。

 

二、n/2为奇数。由于n/2是奇数,子问题考虑n/2+1的情况。怎么由n/2+1的情况推出n的情况?

例如n=6时。先考虑它的子问题n=4

        1 2 3 4

        2 1 4 3

        3 4 1 2

        4 3 2 1

由于四号选手是非法的所以:

       1 2 3 0

       2 1 0 3

       3 0 1 2

 同理推出

      1 2 3 0

      2 1 0 3

      3 0 1 2

      4 5 6 0

      5 4 0 6

      6 0 4 5

对第四列(第三天),只有一号选手和四号选手没比赛,那就让他们比。推出

      1 2 3 4

      2 1 5 3

      3 6 1 2

      4 5 6 1

      5 4 2 6

      6 3 4 5

之后的两天,考虑为比过的两位选手比赛就行了。比赛的顺序按未比赛的后几个选手顺序取模。例如前三天出现了 4那后两天为5 6。前三天出现了 5后两天为 6 4

如此处理即可得到

      1 2 3 4 5 6

      2 1 5 3 6 4

      3 6 1 2 4 5

      4 5 6 1 2 3

      5 4 2 6 3 1

      6 3 4 5 1 2


#include<cstdio>#include<cstring>#include<iostream>#include<cmath>using namespace std;int mp[1100][1100];void dfs(int n){    if(n==1)    {        mp[1][1]=1;        return ;    }    if(n&1) n++;    int t=n/2;    dfs(t);    for(int i=1;i<=t;i++)        for(int j=1;j<=t+1;j++)        {            if(mp[i][j]>t)            {                mp[i+t][j]=i;                mp[i][j]=i+t;                int c=i+t+1;                for(int k=t+2;(t&1)&&k<=n;k++,c++)                {                    if(c==i+t)  c++;                    if(c>n) c-=n/2;                    mp[i][k]=c;                    mp[c][k]=i;                }            }            else            {                mp[i+t][j]=mp[i][j]+t;                if((t%2==0)||t==1)                {                    mp[i+t][j+t]=mp[i][j];                    mp[i][j+t]=mp[i+t][j];                }            }        }}int main(){    int n;    while(~scanf("%d",&n))    {        memset(mp,0,sizeof(mp));        if(n&1) dfs(n+1);            else    dfs(n);        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n+(n&1);j++)            {                cout<<(mp[i][j]>n?0:mp[i][j]);                cout<<(j==1?": ":" ");            }            cout<<endl;        }        cout<<endl;    }}

1 0