循环赛日程表问题研究

循环赛日程表问题研究
循环赛日程表问题研究

学年论文

题目循环赛日程表问题研究

学生

指导教师

年级2009级

专业软件工程

系别软件工程

学院计算机科学与信息工程学院

哈尔滨师范大学

2012年6月

论文提要

本文采用分治算法来解决循环赛日程表的安排问题。通过对问题的详细分析,列出1到10个选手的比赛日程表,找出两条规则,作为算法实现的依据,而后采用c语言实现算

法,通过测试分析,程序运行结果正确,运行效率较高。同时也介绍了循环赛日程表问题的另一种解法多边形解法,这种方法另辟蹊径,巧妙地解决了循环赛日程表问题,运行效率较高。

循环赛日程表问题研究

摘要:本文采用分治算法来解决循环赛日程表的安排问题。根据算法的设计结果,采

用c 语言实现算法,通过测试分析,程序运行结果正确,运行效率较高。同时也介绍了循环赛日程表问题的另一种解法,这种方法另辟蹊径,想法独特,运行效率较高。

关键词:循环赛日程表问题;分治法

一、题目描述

设有n 个运动员要进行网球循环赛。设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次;

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

二、问题分析

循环赛日程表可以采用分治法实现,把一个表格分成4个小表格来处理,每个小表格都是一样的处理方法,只是参数不同。分析过程具体如下:

1、n=1

(表2-1)

2.、n=2

(表2-2)

3、n=3

(1) 添加一个虚拟选手4#,构成n+1=4

(2) 4/2=2,分两组,每组各自安排(1 2),(3 4) (3) 每组跟另一组分别比赛(拷贝)这是四个人比赛的

(表2-3) 4人赛程

(4) 把虚选手置为0 (表2-4)3人赛程

1

1 2 2

1 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

0 3 2 1

这是三个人比赛的安排

4、n=4,见表2-3

5、n=5

(1) 加一个虚选手,n+1=6。安排好6个人的比赛后,把第6个人用0表示即得5人的。

(2) 分成两组(1 2 3) (4 5 6),各3名选手

(3) 依照表2-4,安排第1组;按表2-5安排第2组(除0元素外,都加3)

(表2-5)

4 5 6 0

5 4 0 6

6 0 4 5

0 3 2 1

(4) 把表2-5排于表2-4下方

(表2-6)

1 2 3 0

2 1 0 3

3 0 1 2

4 5 6 0

5 4 0 6

6 0 4 5

(5) 把同一天都有空的两组安排在一起比赛(按这种安排,肯定每天只有一对空组)。

(表2-7)

1 2 3 4

2 1 5 3

3 6 1 2

4 5 6 1

5 4 2 6

6 3 4 5

(6) 第一组的(1 2 3)和第2组的(4 5 6)分别比赛。但是由于(1,4), (2, 5), (3 6)已经比

赛过了,所以在后面的安排中不能再安排他们比赛。

1 2 3

4 5 6

首先,1#只能和5#或6#比赛。

(a) 若1#-5#,由于3#和6#已经比赛过,所以只能安排: 2#-6#,3#-4#

(b) 若1#-6#,由于2#和5#已经比赛过,只能安排:2#-4#,3#-5#

这样安排后前三行的后两列,后三行的后两列由上面的三行来定:

(表2-8)6人赛程

1 2 3 4 5 6

2 1 5

3 6 4

3 6 1 2

4 5

4 5 6 1 3 2

5 4 2

6 1 3

6 3 4 5 2 1

表2-8就是6名选手的比赛日程安排。将其中的6号作为虚拟选手,把6换成0,即得5名选手的赛程安排表:

(表2-9)5人赛程

1 2 3 4 5 0

2 1 5

3 0 4

3 0 1 2

4 5

4 5 0 1 3 2

5 4 2 0 1 3

6 3 4 5 2 1

6、n=6,见表2-8。

7、n=7, 添加1,n+1=8。8名选手的安排,由4名选手(表2-3)构成

(表2-10)8人赛程

1 2 3 4 5 6 7 8

2 1 4

3 6 5 8 7

3 4 1 2 7 8 5 6

4 3 2 1 8 7 6 5

5 6 7 8 1 2 3 4

6 5 8

7 2 1 4 3

7 8 5 6 3 4 1 2

8 7 6 5 4 3 2 1

将其中的8改成0,即得7名选手的赛程安排。

(表2-11)7人赛程

1 2 3 4 5 6 7 0

2 1 4

3 6 5 0 7

3 4 1 2 7 0 5 6

4 3 2 1 0 7 6 5

5 6 7 0 1 2 3 4

6 5 0

7 2 1 4 3

7 0 5 6 3 4 1 2

0 7 6 5 4 3 2 1

8、n=8 ,见表2-10。

9、n=9,由n+1=10人,将虚选手10号置为0来得到。

10、n=10。10人的比赛,分两组(1 2 3 4 5)和(6 7 8 9 10)各5人。前5人比赛的安排如表2-12

(表2-12)

1 2 3 4 5 0

2 1 5

3 0 4

3 0 1 2

4 5

4 5 0 1 3 2

5 4 2 0 1 3

第2组的5人比赛就是将前5人比赛选手(非0)号对应加5

(表2-13)

6 7 8 9 10 0

7 6 10 8 0 9

8 0 6 7 9 10

9 10 0 6 8 7

10 9 7 0 6 8

然后两组合并,得到表2-14

(表2-14)

1 2 3 4 5 0

2 1 5

3 0 4

3 0 1 2

4 5

4 5 0 1 3 2

5 4 2 0 1 3

6 7 8 9 10 0

7 6 10 8 0 9

8 0 6 7 9 10

9 10 0 6 8 7

10 9 7 0 6 8

找两组中同一天中没有安排比赛的,安排他们比赛:

(表2-15)

1 2 3 4 5 6

2 1 5

3 7 4

3 8 1 2

4 5

4 5 9 1 3 2

5 4 2 10 1 3

6 7 8 9 10 1

7 6 10 8 2 9

8 3 6 7 9 10

9 10 4 6 8 7

10 9 7 5 6 8

由于两组中:

1 2 3 4 5

6 7 8 9 10

按列对应的已经比赛过一次:1-6,2-7,3-8,4-9,5-10。后面再安排两组选手分别比赛的时候,就不考虑已经比赛过的组合。

安排两组选手分别比赛的时候,依照这样的规则:1#按递增顺序依次跟没有比赛过的第2组选手比赛(7,8,9,10各一天)。若1#和x1比赛,则2号从6~10号中从x1之后开始按增序中找第一个没有比赛过的选手,跟他比赛(如果x1=10,则2号从6号开始按增序找)。3、4、5号也如此找。结果如表2-16所示:

(表2-16)10人的赛程安排

1 2 3 4 5 6 7 8 9 10

2 1 5

3 7

4 8 9 10 6

3 8 1 2

4

5 9 10

6 7

4 5 9 1 3 2 10 6 7 8

5 4 2 10 1 3

6

7

8 9

6 7 8 9 10 1 5 4 3 2

7 6 10 8 2 9 1 5 4 3

8 3 6 7 9 10 2 1 5 4

9 10 4 6 8 7 3 2 1 5

10 9 7 5 6 8 4 3 2 1

观察表2-16的右上角,发现如下规律(表2-8,6人比赛时,也有此规律):

【规则一】:每一行数值从左到右循环递增;每一列上也是6~10(即n/2+1~n)循环递增(取到最大值10之后,下一个数字又从6开始取值;而且不包含左上角的块同一行中取过的值)。第一行第m+1(下标从0开始)列的值为(m+1)+1,依次向右递增;要先处理。其他行上的值要依赖于它的这个取值。

【规则二】:右下角的块:因为比赛是两两之间进行的,所以右下角由右上角决定(比赛的对手是两个人,因此对应的安排要成对);

OK,至此,问题就好解决了,只要按照这个规律填数字,就可以得到一种合理的安排。

由于我们不是求全部的安排,所以,只要得到这么一个解就可以了。

9人比赛,则将表2-16中的10全部用0代替即得。

(表2-17)9人的赛程安排

1 2 3 4 5 6 7 8 9 0

2 1 5

3 7

4 8 9 0 6

3 8 1 2

4

5 9 0

6 7

4 5 9 1 3 2 0 6 7 8

5 4 2 0 1 3

6

7

8 9

6 7 8 9 0 1 5 4 3 2

7 6 0 8 2 9 1 5 4 3

8 3 6 7 9 0 2 1 5 4

9 0 4 6 8 7 3 2 1 5

0 9 7 5 6 8 4 3 2 1

三、算法设计

n名选手的赛程安排问题:

1、如果n为偶数,可分为两个n/2人的组,分别比赛,然后两组间比赛。

(1)如果n/2为偶数,左下角为左上角加n/2来得到,然后左下角拷贝到右上角;左上角拷贝到右下角;

(2)如果n/2为奇数,先安排左下角(除0外都加n/2),然后把同一天都有空的选手安排比赛。然后,右上角要按规则一来完成,右下角由规则二来定。

2、如果n为奇数,则加1个选手使n+1成为偶数。转化成偶数名选手的赛程安排问题

来解决。最后把虚拟选手n+1号所在位置上的值置为0。即完成安排。

四、算法改进

循环赛要求比赛的每两个选手都要进行一次比赛,而且每个选手每天都要比赛一场。这种题目的解法通常是用分治的思想来做,并且是分治方法解题的经典题目。下面的一种受多边形启发的方法,也能巧妙解决循环赛日程表问题。

多边形解法:有n个选手要进行循环赛,画n边形,每个点表示一个选手。在同一水平线上的选手进行比赛。每天的比赛由旋转一次的多边形决定,每次顺时针旋转360/n度。例如:

(1)假设有5名运动员(每天将有一名队员轮空),则可建立一个如下五边多边形:

1 2

5 3

4

所以第一天4号轮空,对局为1-2和5-3

(2)第二天顺时针旋转360/5度,即为:

5 1

4 2

3

所以第二天3号轮空,对局为1-5和2-4

(3)依此类推,直到第五天,多边形为

2 3

1 4

5

比赛结束,同理,若比赛人数为8人,多边形则为

1 2

8 3

7 4

6 5

依次顺时针旋转360/8度7次后,即比赛进行7天,即可结束比赛

五、算法实现

(1)采用分治法实现代码(c语言实现):

/* 循环赛日程安排问题-采用分治法 */

#include

#include

int **A; //int *指针数组,

int *schedule; //int数组,一维数组保存二维数组的数据int N =1; //问题的规模。初始化时会设定

//isodd:判断x是否奇数,是则返回1,否则0

int isodd(int x)

{

return x&1;

}

//print:打印赛程

void print()

{

int i,j, row, col;

if(isodd(N))

{

row=N;

col=N+1;

}

else

{

row=N;

col=N;

}

printf("第1列是选手编号\n");

for(i=0;i

{

for(j=0;j

{

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

}

printf("\n");

}

}

/*init:初始化,设置问题规模N值,分配内存,用schedule指向;

把A构造成一个二维数组*/

void init()

{ int i, n;

char line[100]={'\0'};

printf("请输入选手人数:");

fgets(line,sizeof(line), stdin);

N=atoi(line);

if(N<=0) exit(-1);

if(isodd(N))

n=N+1;

else

n=N;

//schedule是行化的二维数组

schedule=(int *)calloc(n*n, sizeof(int));

A=(int **)calloc(n, sizeof(int *));

if(!schedule || A==NULL) exit(-2);

for(i=0;i

{

A[i]=schedule+i*n;

A[i][0]=i+1;//初始化这个数组的第一列

}

return;

}

/*replaceVirtual:把第m号虚的选手去掉(换做0)*/

void replaceVirtual(int m)

{

int i,j;

for(i=0;i

{

for (j=0;j<=m;j++) //列: 比行要多1

A[i][j] = (A[i][j]==m)?0:A[i][j];

}

return;

}

/*copyeven:m为偶数时用,由前1组的m位选手的安排,来构成第2组m位选手的赛程安排,以及两组之间的比赛安排 */

void copyeven(int m)

{

if(isodd(m)) return;

int i,j;

for (j=0;j

{

for (i=0;i

{

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

}

}

for (j=m;j<2*m;j++)//两组间比赛的安排

{

for (i=0;i

{

A[i][j]=A[i+m][j-m]; //把左下角拷贝到右上角

}

for (i=m;i<2*m;i++) //3. 对应的,第2组和第1组

{

A[i][j]=A[i-m][j-m]; //把左上角拷贝到右下角

}

}

return;

}

/*copyodd:m为奇数时用,由前1组的m位选手的安排,来构成第2组m位选手的赛程安排,以及两组之间的比赛安排。这时和m为偶数时的

处理有区别。

*/

void copyodd(int m)

{

int i,j;

for (j=0;j<=m;j++) //1. 求第2组的安排(前m天)

{

for (i=0;i

{

if (A[i][j]!=0)

{

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

}

else //特殊处理:两个队各有一名选手有空,安排他们比赛

{

A[i+m][j] = i+1;

A[i][j] = i+m+1;

}

}

}

/*安排两组选手之间的比赛(后m-1天)*/

for(i=0,j=m+1;j<2*m;j++)

{

A[i][j]= j+1; //2. 1号选手的后m-1天比赛

A[ (A[i][j] -1) ][j] = i+1; //3. 他的对手后m-1天的安排

}

//以下的取值要依赖于1号选手的安排,所以之前先安排1号的赛程

for (i=1;i

{

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

{//2. 观察得到的规则一:向下m+1~2*m循环递增

A[i][j] = ((A[i-1][j]+1)%m==0)?A[i-1][j]+1 :m + (A[i-1][j]+1)%m;

//3. 对应第2组的对手也要做相应的安排

A[ (A[i][j]-1) ][j] = i+1;

}

}

return;

}

/*makecopy:当前有m位(偶数)选手,分成两组,每组由m/2位选手构成由第一组的m/2位选手的安排来构成第二组的比赛安排,第一

组与第二组的比赛安排。要区分m/2为奇数和偶数两种情况 */ void makecopy(int m)

{

if (isodd(m/2)) //m/2为奇数

copyodd(m/2);

else //m/2为偶数

copyeven(m/2);

}

void tournament(int m)

{

if(m==1)

{

A[0][0]=1;

return ;

}

else if(isodd(m)) //如果m为奇数,则m+1是偶数

{

tournament(m+1); //按照偶数个选手来求解

replaceVirtual(m+1); //然后把第m+1号虚选手置成0

return ;

}

else //m是偶数,

{

tournament(m/2); //则先安排第1组的m/2人比赛

makecopy(m); //然后根据算法,构造左下、右下、右上、右下的矩阵 }

return ;

}

/*endprogram:回收分配的内存*/

void endprogram()

{

free(schedule);

free(A);

}

int main()

{

init(); //初始化

tournament(N);//求解

print(); //打印结果

endprogram(); //回收内存

getchar();

return 0;

}

(2)多边形法(C语言实现):

/* 采用多边形实现法 */

#include

#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

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[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("1\n");

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 ");

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

}

printf("\n");

}

}

int main()

{

int n;

init();

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

{

tour(n);

out(n);

}

return 0;

}

六、总结

算法实现1采用的分治算法,其基本思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。这是循环赛日程表问题解决方法的经典形式,但是比较复杂,分析起来比较繁琐。而算法实现2采用的多边形解法,其基本思想是,对于n个选手进行的循环赛,画出一个n边形,每个点表示一个选手,在同一水平线上的选手进行比赛,每天的比赛由旋转一次的多边形决定,每次顺时针旋转360/n度。,该解法很巧妙,思想独特,并且容易理解。两者效率差不多,在整体上多边形解法比分治法较优。多边形解法给了我们一个良好的启发,对于一个复杂的问题,往往会有一个很简单的解决方法。

参考文献:

[1] 王晓东:计算机算法分析与设计,电子工业出版社,2006年版。

[2] 严蔚敏吴伟民:数据结构(C语言版),清华大学出版社,1997年版。

学年论文(设计)成绩表

论文题目循环赛日程表问题研究

作者

指导教师职称讲师

指导教师评语

该生在论文中,详细介绍循环赛日程表问题,在对问题进行详细分析论述的基础上提出了两种风格不同的解题策略,对每种策略都给出了实现算法的具体程序。

该生在完成论文的过程中态度认真积极,能及时与老师沟通,按时完成写作进度。该生基本上具有独立分析问题、解决问题的能力。

论文结构清晰,论述完整,观点明确,表达清楚。文章书写工整,格式及标点规范。符合本科生学年论文标准。

指导教师签字等级

循环赛的方法与编排

循环赛的方法与编排 一、循环赛的种类与特点 (一)循环赛的种类 循环赛又称循环法。是指参赛队(或个人,下同)之间,都要互相轮流比赛,最后按照各参赛队在全部比赛中的胜负场数、得分多少排定名次的比赛方法。它在对抗性项目比赛中经常被采用。循环赛包括单循环、双循环或分组循环三种。单循环是所有参赛队(人)相互轮赛一次;双循环是所有参赛队(人)相互轮赛二次;分组循环是参赛队(人)较多时,采用种子法,把强队(人)分散在各组,先进行小组单循环赛,再根据小组名次来组织第二阶段的比赛。主办单位可根据参赛队多少和比赛期限的长短以及项目特点而灵活选用。一般情况下,单循环宜在参赛队不太多,比赛时间与场地又比较充裕时采用;分组循环大多是在参赛队数多,比赛时间又不能过长,并尽量为参赛队提供比赛机会,使比赛能较合理地排定名次时采用。 (二)循环赛的特点 采用循环法进行比赛,总的优点是参赛队机会均等,实战和互相观摩学习的机会多,能准确地反映出参赛队之间真正的技术水平的高低,客观地排定参赛队的名次,比赛结果的偶然性和机遇性小。上述优点正是淘汰赛的主要缺点,但循环赛自身也存在有某些不足与矛盾,应引起组织者的重视。 1.比赛总的期限长,占用场地和时间多,当参赛队(人)多时,直接采用大循环赛有一定困难,应用范围上有一定的局限性。 2.如何合理地安排比赛的顺序,避免在比赛时间、间隙、地点、场次和比赛条件等方面出现的不均衡现象。 3.当比赛结果有两个或两个以上队的胜负场数相同,得失分相等时,如何根据不同项目的特点,科学地解决好最后名次的排定。 二、循环赛的轮数与场数计算 (一)循环赛的轮数 每个参赛队赛毕一场(轮空队除外),称为一轮结束。计算循环赛的轮数,目的在于计划整个比赛所需用的时间或期限,是比赛日程安排的主要依据。其计算方法:Y=轮次数,N=参赛队数 如果参赛队为偶数Y=N-1 即轮次数=参赛队数-1 如果参赛队为奇数,则:比赛轮数=参赛队数。 注:双循环赛的轮数是单循环赛轮数的加倍。 (二)循环赛的场数 循环赛的场数是指参赛队之间互相轮流比赛全部结束的总场数。计算循环赛的比赛总场数,目的在于计划安排人力、物力、比赛日程与场地。其计算方法如下: X=N×(N-1)÷2 X为比赛场数,N为参赛队数。 单循环比赛场数=参赛队数×(参赛队数-1)÷2 双循环比赛的总场数=参赛队数×(参赛队数-1) 三、循环比赛顺序的编排方法与注意事项 (一)单循环比赛顺序的编排方法 1.轮次表的安排方法

网球循环赛日程表

一、问题表述: 设有n个运动员要进行网球循环赛。设计一个满足以下要 求的比赛日程表, (1)每个选手必须与其他n-1个选手各赛一次; (2) 每个选手一天只能赛一次; (3) 当n是偶数时,循环赛进行n-1天,当n是奇数时,循环 赛进行n天 二、分析问题 题目是要n名运动员进行循环比赛。当n为偶数时,正好每天都可以两两一组,与其余的n-1个选手比赛,只需n-1天; 而当n为奇数,每天将有一个选手轮空,比赛将持续n天。 可以采用的算法如下: 1.算法一:使用分治法 当n为偶数时,可以讲问题分为两个部分n/2; 然后继续划分, 知道最后剩余两名选手单独比赛。当n为奇数时,增设一个虚拟 选手,运动员为n+1个,将问题转化为是偶数的情形。当选手与 虚拟选手比赛时,表示轮空,因此只需要关注n为偶数的情形。 a)当n/2为偶数时,与n = 2^k情形类此。 b)当n/2为奇数时,增设一个虚拟的选手,递归返回的将有轮 空的选手,可以讲在前面n/2轮比赛的选手与后面n/2轮空的 选手进行比赛。 2.算法二:利用边是奇数的正多边形。 特点:以多边形中的任意一个顶点画对称轴,其余偶数对顶点相 互对称。 N名选手编号为1~n,将其画成一个正多边形。 a)所以当n为奇数时,第一天1号休息,其余以一号为对称轴, 两两对称打比赛,第二天开始一次轮流休息,其余一休息的 那个人编号为对称轴,两两比赛。这样比赛可进行n天。如 图:

b) 当n 为偶数时,取出编号最大的,其他的组成一个正多边形,n 号一次顺序与1,2,。。。n-1号选手比赛,其他与a )相同。如图所示:(图中是从0开始编号)

第一节 循环赛的方法与编排

第一节循环赛的方法与编排 一、循环赛的种类与特点 (一)循环赛的种类 1、概念循环赛又称循环法。指参赛队(人)之间,都相互轮流比赛,最后按照各参赛队在全部比赛中的胜负场数、得分多少排定名次的比赛方法。 2、分类循环赛包括单循环、双循环和分组循环三种。 单循环是所有参赛队(人)相互轮赛一次;一般在参赛队人不太多,场地和时间比较充裕时采用。 双循环是所有参赛队(人)相互轮赛二次;一般在参赛队人不多,场地和时间比较充裕时采用。 分组循环是参赛队(人)较多时,采用种子法,把强队(人)分散在各组,先进行小组循环,再根据小组名次组织第二阶段的比赛。一般在参赛队人多,场地和时间较紧时采用。 (二)循环赛的优缺点 优点:参赛队机会均等,实战和相互观摩学习的机会多,能准确反映出参赛队之间真正的技术水平的高低,客观地排定参赛队的名次,比赛结果的偶然性和机遇小。 缺点: 1、比赛总的期限长,站用场地和时间多,当参赛队人多时,直接采用大循环有一定的困难,应用范围具有一定的局限性。 2、如何合理安排比赛的顺序,避免在比赛时间、间隙、地点、场次和比赛条件等方面出现不均衡现象。 3、当比赛结果有两个或两个以上队人的胜负场数相同,得失分相等时,如何根据不同项目的特点,科学地解决好最后的名次排定。 二、循环赛的轮数与场数计算 (一)循环赛的轮数 每个参赛队赛完一场(轮空队除外),称为一轮结束。计算循环赛的轮数的目的在于计划整个比赛所需要的时间和期限,是比赛日程安排的主要依据。 计算方法: 1、单循环 当N=2n时,Y=N-1 当N=2n-1时,Y=N (其中Y=轮次数,N=参赛对数) 2、双循环和多循环为单循环的倍数。 (二)循环赛的场数 循环赛的场数是指参赛队人之间相互轮流比赛全部结束

循环赛日程表问题研究

学年论文 题目循环赛日程表问题研究 学生 指导教师 年级2009级 专业软件工程 系别软件工程 学院计算机科学与信息工程学院 哈尔滨师范大学 2012年6月 论文提要 本文采用分治算法来解决循环赛日程表的安排问题。通过对问题的详细分析,列出1到10个选手的比赛日程表,找出两条规则,作为算法实现的依据,而后采用c语言实现算

法,通过测试分析,程序运行结果正确,运行效率较高。同时也介绍了循环赛日程表问题的另一种解法多边形解法,这种方法另辟蹊径,巧妙地解决了循环赛日程表问题,运行效率较高。 循环赛日程表问题研究 摘要:本文采用分治算法来解决循环赛日程表的安排问题。根据算法的设计结果,采

用c 语言实现算法,通过测试分析,程序运行结果正确,运行效率较高。同时也介绍了循环赛日程表问题的另一种解法,这种方法另辟蹊径,想法独特,运行效率较高。 关键词:循环赛日程表问题;分治法 一、题目描述 设有n 个运动员要进行网球循环赛。设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次; (3)当n 是偶数时,循环赛进行n-1天。当n 是奇数时,循环赛进行n 天。 二、问题分析 循环赛日程表可以采用分治法实现,把一个表格分成4个小表格来处理,每个小表格都是一样的处理方法,只是参数不同。分析过程具体如下: 1、n=1 (表2-1) 2.、n=2 (表2-2) 3、n=3 (1) 添加一个虚拟选手4#,构成n+1=4 (2) 4/2=2,分两组,每组各自安排(1 2),(3 4) (3) 每组跟另一组分别比赛(拷贝)这是四个人比赛的 (表2-3) 4人赛程 (4) 把虚选手置为0 (表2-4)3人赛程 1 1 2 2 1 1 2 3 4 2 1 4 3 3 4 1 2 4 3 2 1

(完整word版)分治法循环赛日程表实验报告

西北农林科技大学信息工程学院《算法分析与设计》综合训练实习报告 题目:分治法循环赛日程表 学号 姓名 专业班级 指导教师 实践日期2011年5月16日-5月20日

目录 一、综合训练目的与要求 (1) 二、综合训练任务描述 (1) 三、算法设计 (1) 四、详细设计及说明 (3) 五、调试与测试 (4) 六、实习日志 (6) 七、实习总结 (6) 八、附录:核心代码清单 (6)

一、综合训练目的与要求 本综合训练是软件工程专业重要的实践性环节之一,是在学生学习完《算法分析》课程后进行的综合练习。本课综合训练的目的和任务: (1)巩固和加深学生对算法分析课程基本知识的理解和掌握; (2)培养利用算法知识解决实际问题的能力; (3)掌握利用程序设计语言进行算法程序的开发、调试、测试的能力; (4)掌握书写算法设计说明文档的能力; (5)提高综合运用算法、程序设计语言、数据结构知识的能力。 二、综合训练任务描述 假设有n=2k 个运动员要进行网球循环赛。设计一个满足一下要求的比赛日程表:(1)每个选手必须与其他n-1个选手各赛一次 (2)每个选手一天只能赛一次 (3)循环赛一共进行n-1天 利用Java语言开发一个界面,输入运动员的个数,输出比赛日程表。对于输入运动员数目不满足n=2k时,弹出信息提示用户。 三、算法设计 (1) 文字描述 假设n位选手顺序编号为1,2,3……n,比赛的日程表是一个n行n-1列的表格。第i行j列表示第i号选手在第j天的比赛对手,根据分治法,要求n个选手的比赛日程,只要知道其中一半的比赛日程,所以使用递归最终可以分到计算两位选手的比赛日程,然后逐级合并,得出结果。 (2) 框图

用C++编写循环赛日程表

循环赛日程表 问题描述:设有n位选手参加网球循环赛,n=2^k,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天比赛一场,不能轮空,按一下要求为比赛安排日程, (1)每位选手必须与其他n-1格选手格赛一场; (2)每个选手每天只能赛一场; (3)循环赛一共进行n-1天; #include int a[50][50]; void table (int x,int k) //此函数为从x号球员起的共2的k次方名球员的安排日程表 { int i,j,y=1; if(k==1)//只有两名球员 { a[x][0]=x; a[x][1]=x+1; a[x+1][0]=x+1; a[x+1][1]=x; } else { for(i=1;i<=k-1;i++) {y=y*2;} table(x,k-1); table(x+y,k-1); for(i=x;i

int n=1; cout<<"请输入k值"<>k; for(i=1;i<=k;i++) {n=n*2;} cout<<"参赛人数"<<" "<

算法分析实验报告--分治策略

分治策略 姓名:XXX 专业班级:XXX 学号:XXX 指导教师:XXX 完成日期:XXX

一、试验名称:分治策略 (1)写出源程序,并编译运行 (2)详细记录程序调试及运行结果 二、实验目的 (1)了解分治策略算法思想 (2)掌握快速排序、归并排序算法 (3)了解其他分治问题典型算法 三、实验内容 (1)编写一个简单的程序,实现归并排序。 (2)编写一段程序,实现快速排序。 (3)编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现 要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四、算法思想分析 (1)编写一个简单的程序,实现归并排序。 将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行 排序,最终将排好序的子集合合并成为所要求的排好序的集合。 (2)编写一段程序,实现快速排序。 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有 数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数 据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据 变成有序序列。 (3)编写程序实现循环日赛表。 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通 过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割, 直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让

这2个选手进行比赛就可以了。 五、算法源代码及用户程序 (1)编写一个简单的程序,实现归并排序。 #include #include<> #define MAX 10 using namespace std; void merge(int array[],int p,int q,int r) { int i,k; int begin1,end1,begin2,end2; int* temp = new int[r-p+1]; begin1 = p; end1 = q; begin2 = q+1; end2 = r; k = 0; while((begin1 <= end1)&&(begin2 <= end2)) { if(array[begin1] < array[begin2]) { temp[k] = array[begin1]; begin1++; } else { temp[k] = array[begin2]; begin2++; } k++; } while(begin1 <= end1) { temp[k++] = array[begin1++]; }

单循环赛日程表

题目:循环赛日程表 设计一个满足一下要求的比赛日程表 (1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次; (3)若才赛选手为偶数,循环赛一共进行n-1天;若参赛选手为奇数循环赛一共进行n天。主要思想:“贝格尔”编排法,其优点是单数队参加时可避免第二轮的轮空队从第四轮起每场都与前一轮的轮空队比赛的不合理现象。 方法如下: 所谓贝格尔编排法,第一轮开始的编排同传统方法一样,假设现在有7个队参加单循环,分别抽签成为1-7队,由于贝格尔编排法必须是双数队,所以再加一个0队,与0队比赛表示该队轮空,现在必须定下一个数为参照数,因此我们假设0为参照数(任意数都可以,一般取0或者最大数),第一轮的对阵形式如下: 1 – 0 2 – 7 3 – 6 4 – 5 这个大家都能看明白,这跟贝格尔编排法无关,第二轮则开始相关了。在第一轮中,0在右边,现在我们要在第二轮让它换成左边,第三轮又让它换回右边,反反复复,到最后一轮即第七轮时,它还是在右边。我们把0安排好后,再把第一轮右下角的5提到右上角来,因此第二轮的第一场比赛就变成: 0 – 5 然后我们还要回到第一轮的八个数字来,我们假设它是一个环,无论是顺时针还是逆时针,它们的位置是相对固定的(除了它们与0的位置有时候会改变外,因为0的位置是先定好的),比如按照顺时针方向看,5的前面是6,后面是4,因此,第二轮我们还是安排5的前面是6,后面是4,0我们假设它不存在,于是第二轮的第一、二场比赛就是: 0 – 5 6 – 4 那其他怎么办呢,照旧轮呗,就像排球的轮转一样,于是第二轮就是 0 – 5 6 – 4 7 – 3 1 – 2 其他依次类推。 无论比赛队是单数还是双数,最后一轮时,必定是“0”或最大的一个代号在右上角,“1”在右下角。 根据参赛队的个数不同,应按规定的间隔数移动(见表)。 间隔移动

分支算法循环赛日程表课程设计

摘要 分治算法在实际中有广泛的应用,例如,对于n个元素的排序问题,当n = 1 时,不需任何计算;当n = 2 时,只要做一次比较即可排好序;当n = 3时只要做两次比较即可……而当n较大时,问题就不容易那么处理了。要想直接解决一个较大的问题,有时是相当困难的。分治算法的基本思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。如果原问题可分割成k个子问题,1 < k < n+1,且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治算法就是可行的。由分治算法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易求出其解。由此自然引出递归算法。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。 本次课程设计正是采用分治算法来解决循环赛日程表的安排问题。根据算法的设计结果,采用c语言实现算法,通过测试分析,程序运行结果正确,运行效率较高。 关键词:分治算法

目录 摘要 ..................................................................................................................... I 1 问题描述 (1) 2 问题分析 (2) 3 算法设计 (3) 4 算法实现 (7) 5 测试分析 (11) 结论 (12) 参考文献 (13)

1 问题描述 设有n位选手参加网球循环赛,n=2k,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天比赛一场,不能轮空,按以下要求为比赛安排日程, 1)每位选手必须与其他n-1格选手格赛一场; 2)每个选手每天只能赛一场; 3)循环赛一共进行n-1天; 请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行和第j列处填入第i个选手在第j天所遇到的选手,其中1≤i≤n,1≤j≤n-1。

循环赛日程表_文档

循环赛日程表文档 一、问题描述: 设有n个运动员要进行循环赛。现要设计一个满足以下要求的比赛日程表: 1.每个选手必须与其他n-1个选手各赛一次; 2.每个选手一天只能参赛一次; 3.n是偶数时,循环赛在n-1天内结束。n是奇数时,循环赛进行n天. 二:程序源代码: #include #include void Table ( int **a , int n); int main() { int i=1,j; int days,n; int **a; //日程表数组 printf("请输入运动员人数:"); scanf("%d",&n); if (n<=1) printf("不可能出现此数据"); else { a=new int* [n+1]; //行表示运动员 days = n%2==0?n-1:n; //比赛天数,n是偶数时,n-1天。n是奇数时,n 天. for(i=1;i<=(n+1);i++) a[i] = new int [days+1]; } if(n%2!=0) Table(a,n); else { Table(a,n-1); //加入第n个运动员的比赛日程,只需将其加入到前n-1个运动员日程中轮空位置即可 for(i=1;i<=n;i++) { a[i][i]=n;

a[n][i]=i; } } //输出表头 printf("\n "); for(j=1;j<=days;j++) printf("第%d天 ",j); printf("\n"); //输出比赛日程 for(i=1;i<=n;i++) { printf("第%d号 ",i); for(j=1;j<=days;j++) printf("%d ",a[i][j]); printf("\n"); } printf("\n"); system("pause"); } void Table ( int **a , int n) { int i,j,m1,m2; int *b; //指向对阵关系数组 //建立初始对阵关系(,n-1,2,n-2,...,i,n-i) b=new int [n]; //0下标不用 for(i=1;i<=n/2;i++) { b[2*i-1]=i; b[2*i]=n-i; } for(i=1;i<=n;i++)//i控制天数变化 { a[i][i]=0; //n为奇数时在第i天第i号运动员轮空 for(j=1;j<=(n-1);j+=2) { //第i天m1与m2对阵 m1=((b[j]+i)<=n)?(b[j]+i):(b[j]+i)%n; m2=((b[j+1]+i)<=n)?(b[j+1]+i):(b[j+1]+i)%n; a[m1][i]=m2; a[m2][i]=m1; }

循环赛日程表设计源代码

#include #include const int N=100; int a[N][N]; void Copy(int i1,int j1,int i2,int j2,int n){ for(int k1=0;k1

单循环比赛日程安排

单循环比赛日程安排 一、摘要: 本文在合理假设的基础上由问题的数学实质,建立出问题的模板模型,并根据问题的特殊性将模板分为奇数和偶数两种来研究,运用归纳的方法发现了列出矩阵后的特殊规律,根据这些规律得出一般模型,把模型与矩阵相对应,即得出日程安排的结果,并把模型一般化,使之能广泛应用于日程安排中,给出一个性能指标,用于判断日程安排是否公平、适合 对模型进行了推广。 二、问题重述: 1)七支球队进行单循环比赛,每天一场,每个队伍在两场比赛之间至少间隔一天, 2)若变成八支,九支,如何安排合理。能是两只球队至少 间隔两天吗。 3)推广到N支球队的比赛,如何安排,每支球队两场比赛之间至少间隔多少天。 4)你建议用那些指标衡量比赛日程的优劣,如何使这些指标达到最优。 三、建模假设: 1)每天的同一天进行比赛。

2)符号假设 i j 第i 队与第j 队比赛 [x]第x 场比赛 x(ij)第i 队与第j 队的比赛在第x(ij)场 N 球队的总支数 四、分析与建立模型: (1) 建模思路:首先用矩阵的方式把每场比赛列出来(顺序列出),从矩阵中的到一定规律,通过专业人士以前得出的日程安排概况,按一定规律建立一个模板,把矩阵与模板相应的值对应,比赛日期=比赛开始日期+x(ij)-1。 首先,建立一个关于x(ij)矩阵,i 代表行,j 代表列。 ???? ??? ???? ??? ??? ?? ? ? ?)77() 76() 75() 74() 73() 72()71()67()66()65()64()63()62()61()57()56()55()54()53()52()51()47()46()45()44()43()42()41()37()36()35()34()33()32()31() 27()26()25()24()23()22()21()17()16()15()14()13()12() 11(x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x ii 这种情况不存在,ij 与ji 意义相同,为了简便,我们只看对角线上半部分, 既得:

算法实验二(题库)二

南通大学 算法设计与分析 实验报告 姓名:鹿瑶 班级:软件工程122 学号:1213042037

日期:2014 . 12 . 16 目录 Question-2编程实现循环赛日程表(分治法) (3) Question-3编程实现最长公共子序列(动态规划) (3) Question-4 The Triangle(动态规划) (4) Question-5超级台阶(动态规划) (5) Question-6最大和(动态规划) (6) Question-7 剑客决斗(动态规划) (7) Question-8最长上升子序列问题(动态规划) (8) Question-9独木舟上的旅行(贪婪法) (9) Question-10背包问题(贪心算法) (10) Question-11田忌赛马(动规中的贪心算法) (10) Question-12硬币问题(贪心算法) (11) 附:源代码 (12)

Question-2编程实现循环赛日程表(分治法) 描述 设有n=2 k 个运动员要进行网球循环赛,先要设计一个满足一下要求的比赛日常表: (1)每个选手必须与其他n-1 个选手各赛一次 (2)每个选手一天只能赛一次 (3)循环赛一共进行n-1 天 算法设计 将n*n个格子,也就是n阶方阵从中间十字划分,一次划分分成四块,令其右上角和左下角的数据完全相同,右下角和左上角的数据完全相同;每次划分都得到了若干个n/2阶的方阵,然后对这些方阵进行操作,继续令其右上角和左下角的数据完全相同,右下角和左上角的数据完全相同,如此循环下去,直至n<2时结束递归。 运行结果 Question-3编程实现最长公共子序列(动态规划) 描述 如题,需要你做的就是写一个程序,得出最长公共子序列。 tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列S ,如果分别是两个或多个已知序列的子序列,且是 所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列。 输入 第一行给出一个整数N(0和Y=的最长公共

要求:编写程序,用分治法求解循环赛日程表。

要求:编写程序,用分治法求解循环赛日程表。 一、实验目的与要求 1、掌握网球循环赛日程表的算法; 2、初步掌握分治算法 二、实验题: 问题描述:有n=2^k个运动员要进行循环赛。现要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其他n-1个选手各赛一次 (2)每个选手一天只能赛一次 (3)循环赛一共进行n-1天 三、实验代码 #include #include #define MAX 1024 int a[MAX][MAX]; void Copy(int tox, int toy, int fromx, int fromy, int n) { int i, j; for (i=0; i

循环赛日程表

算法设计与分析实验报告循环赛日程表

一.问题描述 设有n位选手参加循环赛,设计循环赛日程表,要求: 每位选手必须和其余n-1个选手比赛; 每位选手每天只能比一场比赛; 若n为奇数,则比赛n天; 若n为偶数,则比赛n-1天。 二.实验目的 熟悉分治法的思想并掌握其运用。 三.实现方式 编译环境:Dev-C++ 算法思路: 使用分治法的思想,给n个选手安排日程表转化为给n/2个选手安排日程表,直到问题规模变成给两个选手安排日程。 日程表可以用一个二维数组表示,数组的大小为k (n<=2^k),第i行第j列的数组值表示第i个选手在第j-1 天比赛的对手(第1列表示选手的编号,假定选手的编号为1, 2,3…恰为数组的行数)。 划分:n个选手的日程表可以由n/2个选手的日程表合并而得。 解决:当只有两个选手比赛的时候,可以直接给出其日程表,得到一个2×2的数组。

当有4个选手参加比赛的时候,则将两个2×2的数组合并,得到一个4×4的数组。 以此类推,n 个选手的日程表由n-1个选手的日程表合并而成。合并规则为: 若n 为偶数,则会得到一个n ×n 的表格;若n 为奇数,需要比赛n 天,则会得到一个n ×(n+1)的表格且每一天必定有一位选手轮空。因此在合并的时候要先把表格扩充为(n+1)×(n+1)的表格,然后再消除虚拟的选手(用0表示轮空)。 例:n=3时赛程表为: 当n=6时,将两个n=3的赛程表合并,在同一天轮空的选手便可 在该天比赛。然后再补上表格右边的元素。

设当前要合并的数组的长度为s,表格左下角的元素可由左上角的元素+s而得: 表格右上角的元素由前一行决定: 表格右下角的元素由表格右上角对应元素所决定:

循环赛日程表分治算法(c语言)

/* *设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表: *每个选手必须与其他n-1个选手各赛一次; *每个选手一天只能参赛一次; *xx在n-1天内结束。 *数组a[i][j]第i个选手在第j天所遇到的选手。*/ #include #include void gametable(int k){int a[100][100]; int n,temp,i,j,p,t; n=2;//k=0两个参赛选手日程可以直接求得 a[1][1]=1;a[1][2]=2; a[2][1]=2;a[2][2]=1; for(t=1;t

for(i=temp+1;i<=n;i++)//将左上角元素抄到右下角 for(j=temp+1;j<=n;j++) a[i][j]=a[i-temp][j-temp];}printf("参赛人数为: %d\n(第i行第j列表示和第i个选手在第j天比赛的选手序号)\n",n);for(i=1;i<=n;i++) for(j=1;j<=n;j++){printf("%d ",a[i][j]); if(j==n) printf("\n");}} void main(){int k; printf("比赛选手个数为n(n=2^k),请输入参数K(K>0): \n"); scanf("%d",&k); if(k!=0) gametable(k);}

相关文档
最新文档