因为时下的java程序员被骂素质差,
所以今日要发一个算法日志,证明我是懂算法的,汗......
这是我数据结构课程设计算法之一
(GDPU)课程设计问题描述: 说明:设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次; (2)每个选手一天只能赛一次; (3)循环赛一共进行n-1天。 设计要求:请使用C语言编程,设计一个有效的算法解决循环赛日程表问题。
网上能找到的答案是使用分治法,
我这里自己写的多边形匹配算法,其他地方没有现成代码能找到的
同时提供思想,和算法实现
实现方法一:多边形算法思想:
首先我们在循环赛中,要实现选手两两配对,因为每天选手只能参加一场比赛,
所以我们要设计一个配对方式既能够适宜计算机存储和运算,又能够高效解决问题的算法。
这里先给出算法策略:两两点匹配,并且匹配的每组点,相邻点的间隔不能相同
(如下图2)
编号1与编号2相邻,
编号3与编号5相隔一个点,
编号4与编号7相邻2个点
这时候,我们以多边形中心为轴,旋转8个点组成的多边形,
其中红线为配对线,不需要变化,
每转360度,代表一天的赛事,以各红线两端编号两两配对,
然而,这样的图设计不能完全覆盖所有的配对旋转时覆盖的路径,
因为剩下8与6,如果我们给它配对,但他们相邻也是1个点,跟3和5重复了
这时候,我们重新设计路径覆盖的配对,(如图3)
我们只要把其中的编号1移到中心轴,外圈是奇数点,
这样,先连接1和2,然后在2的左右分别取点,8和3,7和4,5和6
这样,以1为中心旋转就完全覆盖所有路径,
设N人参加比赛,那么我们需要旋转N-2次的多边形就可以完全覆盖
然后,我们需要进行算法的设计
如何存储配对信息呢?
我们可以设立一个数组queue[]
for(i=1;i<=m;i++){ a[i][1]=i; queue[i]=i+1; ..........1 queue[m+i]=i+1; ............2 }
这样我们的1和2语句赋值后为queue={null,2,3,4,5,6,7,2,3,4,5,6,7}
其中,为了方便操作,不使用下标为0的数组元素queue[0],我们表示为null
而核心算法如下
for(i=1;i<=m;i++){ a[1][i+1]=queue[i];//某天与1对赛的选手,为1的对手编赛程 a[queue[i]][i+1]=1;//以1为中心,为1编赛程 for(int j = 1; j<=m/2;j++){//这里是配对选手的循环 int k=queue[i+j]; int r=queue[i+m-j]; a[k][i+1]=r; a[r][i+1]=k; } }
其中 int k=queue[i+j];
int r=queue[i+m-j];
是实现如图三的覆盖配对取值,
因为queue={null,2,3,4,5,6,7,2,3,4,5,6,7}
queue[i+j] 与 queue[i+m-j] 就可以取到适当的值了
如下是9位选手参赛运行的结果(第一列为参赛选手编号)
实现方法二:分治法
这里假设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得到.
如图:我们要计算8X8矩阵日程,可以通过求左上角4X4矩阵得到,若要求左上角4X4矩阵可以通过求左上角2X2矩阵得到,如此,我们采用分治法通过递归便可求得最终日程表
分治法具体实现请google一下吧,这里不提供源码了