循环赛日程表算法c语言
分治算法实验报告(C语言)
实验1、《分治算法实验》一、实验目的1. 了解分治策略算法思想2. 掌握快速排序、归并排序算法3. 了解其他分治问题典型算法二、实验内容1.编写一个简单的程序,实现归并排序。
2. 编写一段程序,实现快速排序。
3. 编写程序实现循环赛日程表。
设有n=2k个运动员要进行网球循环赛。
现要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天三、算法思想分析1.归并排序先是将待排序集合分成两个大小大致相同的集合,分别对每个集合进行排序,递归调用归并排序函数,再是调用合并函数,将两个集合归并为一个排好序的集合。
2.快速排序先是选择关键数据作为比较量,然后将数组中比它小的数都放到它的左边,比它大的数放大右边,再对左右区间重复上一步,直至各个区间只有一个数。
3.循环赛日程表先将选手分为两部分,分别排序,再将两部分合并,合并时由于循环赛的规律得知直接将左上角的排序表复制到右下角,左下角的排序表复制到右上角即可。
分成两部分时需要利用递归不断分下去直至只剩下一位选手。
四、实验过程分析1.通过归并算法我对分治算法有了初步的实际操作经验,快速排序与归并算法有很大的相似点,但是在合并时的方法不一样,而循环赛日程表则是思路问题,这个题目编程难点应该在于合并时数组调用的for循环的次数以及起始位置问题。
2.对于分治算法一般是将大规模问题分解为小问题,通过递归不断分下去,然后对每个小规模用一个函数去求解。
适用于小规模独立且易解,可以合并到大问题具有最优子结构的问题。
3.归并排序和快速排序熟悉书本及PPT基本没有问题,循环赛日程表则是纠结了很久,一开始算法思路并不是十分清晰所以错了很多次,后来想了很久再观察PPT的循环赛日程表得知最终算法,编写代码中遇到了一个小问题,有一部分选手未排序,如图所示:图中有部分选手未排序,即左下角排序出现了问题,后来直接静态调试,自己按照代码用实际数据去试了一遍,发现是排序时的for循环的次数不对。
网球循环赛日程表
一、问题表述:设有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天。
如图:12345678012345678对称轴此时n=9,为奇数,从0开始每天有一个人轮空对称轴b) 当n 为偶数时,取出编号最大的,其他的组成一个正多边形,n 号一次顺序与1,2,。
n -1号选手比赛,其他与a )相同。
如图所示:(图中是从0开始编号)123456789 9N=2k 时9三、 理论分析算法及实现1. 算法一:使用分治法a) 算法的思路:按分治策略,可以将所有的选手对分为两组(如果n 是偶数,则直接分为n/2每组,如果n 是奇数,则取(n+1)/2每组),n 个选手的比赛日程表就可以通过为(n/2或(n+1)/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人赛程11 2 21 1234 2 1 4 3 3 4 1 2 43211 2 3 0 2 1 0 3 3120 3 2 1这是三个人比赛的安排4、n=4,见表2-35、n=5(1) 加一个虚选手,n+1=6。
安排好6个人的比赛后,把第6个人用0表示即得5人的。
用C++编写循环赛日程表
循环赛日程表问题描述:设有n位选手参加网球循环赛,n=2^k,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天比赛一场,不能轮空,按一下要求为比赛安排日程,(1)每位选手必须与其他n-1格选手格赛一场;(2)每个选手每天只能赛一场;(3)循环赛一共进行n-1天;#include<iostream.h>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<x+y;i++){for(j=y;j<2*y;j++)a[i][j]=a[i+y][j-y];}for(i=x+y;i<x+2*y;i++){for(j=y;j<2*y;j++)a[i][j]=a[i-y][j-y];}}}void main(){int i,j,k;int n=1;cout<<"请输入k值"<<endl;cin>>k;for(i=1;i<=k;i++){n=n*2;}cout<<"参赛人数"<<" "<<n<<endl; table(1,k);cout<<"*****循环赛日程表****"<<endl;cout<<endl;cout<<"日期:";for( i=1;i<n;i++)cout<<" "<<i;cout<<endl;for(i=1;i<n;i++){cout<<endl;for(j=1;j<n;j++)cout<<" "<<a[i][j]<<" ";}cout<<endl;}执行结果如下:。
网球循环赛日程表
一、问题表述:设有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天。
如图:12345678012345678对称轴此时n=9,为奇数,从0开始每天有一个人轮空对称轴b) 当n 为偶数时,取出编号最大的,其他的组成一个正多边形,n 号一次顺序与1,2,。
n -1号选手比赛,其他与a )相同。
如图所示:(图中是从0开始编号)123456789 9N=2k 时9三、 理论分析算法及实现1. 算法一:使用分治法a) 算法的思路:按分治策略,可以将所有的选手对分为两组(如果n 是偶数,则直接分为n/2每组,如果n 是奇数,则取(n+1)/2每组),n 个选手的比赛日程表就可以通过为(n/2或(n+1)/2)个选手设计的比赛日程表来决定。
循环赛日程表_分治法
循环赛⽇程表_分治法题⽬: 设有n=2^k个运动员要进⾏⽹球循环赛。
现要设计⼀各满⾜⼀下要求的⽐赛⽇程表: 1、每个选⼿必须与其他n-1个选⼿各⽐赛⼀次。
2、每个选⼿⼀天只能赛⼀次。
3、循环赛⼀共进⾏n-1天。
按照此要求可以将⽐赛⽇程表设计成⼀个n*n的⼆维表,第⼀列表⽰选⼿,接下来的每⼀列依次表⽰将要⽐赛的每⼀天选⼿。
下⾯以8个选⼿为例:思路: 按照分治法,可将所有选⼿进⾏⼆分,n个选⼿的⽐赛安排可通过n/2个选⼿的⽇程表来决定。
递归地⽤这种⼀分为⼆的策略对选⼿进⾏分割,知道只剩两个选⼿,⽇程表显然直接安排即可。
下图为8个选⼿的⽐赛⽇程表: 图1算法步骤: 1、利⽤⼀个for循环初始化选⼿1的⽇程安排,即图1中的第⼀⾏。
2、根据选⼿1的⽇程安排来安排选⼿2。
此刻为最⼩规模,以相邻的每两天即四个最⼩单元为⼀组,例如选⼿⼀第⼀天要跟选⼿2⽐赛,那么相应选⼿2也要跟选⼿1⽐赛,所以将图1中的第⼀⾏第⼀列序号抄到第⼆⾏第⼆列,将第⼀⾏第⼆列序号抄到第⼆⾏第⼀列。
依次,第3、4列,第5、6列,第7、8列也是。
3、根据选⼿1、2的⽇程安排可以按照左上⾓数据抄到右下⾓,右上⾓数据抄到左下⾓安排出选⼿3、4的⽇程。
4、最后根据前四选⼿,可以将所有⼈的⽇程表都安排出来。
下⾯是java实现完整代码:1package competition;23import java.util.Scanner;45public class Com {6private static Scanner scanner;78public static void main(String [] args) {9int k; //注意,n才是选⼿的⼈数,k只是问题要划分的⼦问题规模数,即n=2^k10 System.out.println("输⼊k:");11 scanner = new Scanner(System.in);12 k=scanner.nextInt();13int a[][]=new int[pow(2,k)+1][pow(2,k)+1];14 table(k, a);15for(int i=1; i<pow(2,k)+1; i++){16for(int j=1; j<pow(2,k); j++){17 System.out.print(a[i][j]+" ");18 }19 System.out.println(a[i][pow(2,k)]);20 }21 }2223static void table(int k, int [][]a){24int n=pow(2,k);25for(int i=1; i<=n; i++) a[1][i]=i;26int m=1;//定义M为记录每⼀次填充时i、j的起始填充位置27for(int s=1; s<=k; s++){//分治规模28 n/=2;29for(int t=1; t<=n; t++)//t是每⼀层分治中进⾏对称的单位的个数30for(int i=m+1; i<=2*m; i++)//控制⾏31for(int j=m+1; j<=2*m; j++){//控制列32 a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];//右下⾓的值等于左上⾓的值33 a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];//左下⾓的值等于右上⾓的值34 }35 m*=2;36 }37 }3839static int pow(int a, int n) {//幂函数40int res=1;41for(int i=0; i<n; i++)42 res*=a;43return res;44 }45 }。
循环赛日程表
//n/2为奇数
代码实现
❖ void copyodd(int n) // n/2为奇数的合并
{
int m=n/2;
for(int i=0;i<m;i++)
{
b[i]=m+i;
b[m+i]=b[i];
}
//未完
代码实现
for(i=0;i<m;i++){
for(int j=0;j<m+1;j++)
}
时间复杂度分析
1. N/2为奇数 T(n)=O(4k)
有2个循环结构 基本语句是循环体内的赋值语句 T(n)=2+(+2)=0(4k),
2.N/2为偶数T(n)=O(4k)
有2个循环结构 基本语句是循环体内的赋值语句 T(n)=3=0(4k),
调试运行
N=4 N=3
3
0
1
3
2
1
0
第输一天出要求<0,(n=4时) 第二天 1>=
0
1
A
1
0
<2, 3>= B<1
,
第一天
0>=
A
B
B
A
第三天
2
3
A
<3
3
2
,
A
B
B
A
2>=
B
输第一出天 要第二求天 (第三n天=4时)
0
1
2
3
1
0
3
2
2
3
0
1
3
2
1
0
AC BD
5循环赛日程表问题
算法实验报告
循环赛日程表
设有n个运动员,设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)当n为偶数时,比赛在一共进行n-1天。
当为奇数时,比赛在一共进行n天。
提示:
对于一般的正整数n,当n是奇数时,增设一个虚拟选手n+1,将问题转换为n是偶数的情形,当选手与虚拟选手比赛时,表示轮空。
因此只要关注n为偶数的情形即可处理。
当n/2为偶数时,与n=2k的情形类似,可用分治法求解。
当n/2为奇数时,递归返回的轮空的比赛要做进一步处理。
其中一种处理是在前n/2比赛中让轮空选手与下一个未参赛选手进行比赛。
【算法-分治策略应用】循环赛日程表问题
【算法-分治策略应⽤】循环赛⽇程表问题⼀、分治策略基本思想1、Divide将原始问题划分或者归结为规模较⼩的⼦问题(多数情况下是划分成2个)2、Conquer递归或迭代求解每个⼦问题3、Combine将⼦问题的解综合得到原问题的解注意:1、⼦问题与原始问题性质完全⼀样2、⼦问题之间可彼此独⽴地求解3、递归停⽌时⼦问题可直接求解⽐较典型的应⽤例⼦是“归并排序法”和“快速排序法”,详细可以参考屈婉玲等编著的《算法设计与分析》(第2版)P26和P37,此处不再赘述。
⼆、题⽬分析和建模1. 问题描述设有n=2k个选⼿要进⾏⽐赛,设计的⽐赛⽇程表需要满⾜以下要求:1)每个选⼿必须与其他n-1个选⼿各赛⼀次;2)每个选⼿⼀天只能赛⼀次;3)整场循环赛⼀共进⾏n-1天。
2. 题⽬建模将⽐赛⽇程表设计成n⾏×n-1列的⼀个表,表中第i⾏第j列的元素表⽰第i个选⼿在第j天所遇到的选⼿。
(1)⾸先看只有两个选⼿的⽇程表(k=1,n=2,2⾏×1列表格,循环赛进⾏1天):表1 循环赛⽇程表(2⼈)(2)四个选⼿的⽇程表(k=2,n=4,4⾏×3列表格,循环赛进⾏3天):⾸先n=22,所以应该退化到求解两个2⼈循环赛的问题,⽇程表构建如下:表1 循环赛⽇程表(2⼈) 表2 循环赛⽇程表(2⼈)将表2抄在表1右侧构成表1*,将表1抄在表2右侧构成表2*,将表1*与表2*按次序上下拼接,构成表3:表3 循环赛⽇程表(4⼈)由于表1和表2中运动员完全不同,拼接之后每⼀⾏和每⼀列都不会存在两个相同号码,也就是说拼接后不会产⽣⼀个选⼿在同⼀天和另外⼀个选⼿⽐赛两次的情况,说明这种拼接是合理的。
(3)⼋个选⼿的⽇程表(k=3,n=8,8⾏×7列表格,循环赛进⾏7天)n=23,⾸先应该退化到4⼈循环赛问题,再退化到2⼈循环赛问题,4⼈退化到2⼈已在(2)中详细描述,此处只说明如何退化到4⼈问题:表3 循环赛⽇程表(4⼈) 表4 循环赛⽇程表(4⼈)拼接⽅法与(2)中相同,构成表5:表5 循环赛⽇程表(8⼈)三、算法设计(1)设计思想:设n=2k采⽤分治策略,将所有参加⽐赛的选⼿分成两部分,n=2k个选⼿的⽐赛⽇程表就可以通过两个n=2k-1个选⼿的⽐赛⽇程表来决定。
循环赛的日程安排题解
循环赛的日程安排题解循环赛是一种比赛形式,参赛队伍之间要进行多轮比赛,每个队伍都要与其他队伍进行一次比赛。
在给定的参赛队伍数量下,如何安排循环赛的日程是一个常见的问题。
对于循环赛的日程安排,有多种方法可以考虑。
下面我将从几个角度来回答这个问题。
1. 完全循环赛:每个队伍都与其他队伍进行一次比赛。
如果参赛队伍的数量是偶数,可以采用以下方法进行日程安排:将参赛队伍分成两组,每组的队伍数量相等。
每轮比赛,将一组的队伍固定在场上,另一组的队伍按照某种规则进行轮换。
每个队伍在比赛结束后,都与另一组的队伍进行比赛,直到所有的比赛都完成。
2. 部分循环赛:如果参赛队伍的数量是奇数,无法进行完全循环赛。
可以考虑以下方法进行日程安排:将参赛队伍分成两组,每组的队伍数量相等。
每轮比赛,将一组的队伍固定在场上,另一组的队伍按照某种规则进行轮换。
每个队伍在比赛结束后,都与另一组的队伍进行比赛,直到所有的比赛都完成。
最后一轮比赛,可以将一组的队伍固定在场上,另一组的队伍轮空,或者可以进行友谊赛。
3. 轮换规则:在循环赛的日程安排中,轮换规则是一个重要的考虑因素。
常见的轮换规则有以下几种:瑞士轮制,根据每个队伍的胜负情况,将队伍分成不同的组别,每轮比赛中,同组别的队伍进行比赛。
轮换表,制定一张表格,按照特定的顺序安排队伍之间的比赛。
随机轮换,通过随机抽签或者其他方式,确定每轮比赛中的对阵情况。
总结起来,循环赛的日程安排需要考虑参赛队伍的数量,以及采用何种轮换规则。
以上所述只是一些常见的方法和思路,具体的日程安排还需要根据实际情况进行调整和制定。
循环赛 C语言代码
cout<<endl;
}
}
else// n ==奇数
{
for(i=0;i<n;i++)
{
for(j=0; j<n+1; j++)//从第1人到第n人,从第1天到第n+1天
{
if(j == 0) a[i][j] = i+1;//第1列为1,2,3,…,n
else
{
{
for(j=1; j<n; j++)
{
if(a[i][j] == a[i][0])a[i][j] = n;//替换冲突的编排
}
}
for(i=0;i<n;i++)
for(j=0; j<n; j++)
if(a[i][j]==8)
a[7][j]=i+1;
//输出
for(i=0;i<n;i++)
{
for(j=0; j<n; j++)
}
//输出
for(i=0;i<n;i++)
{
for(j=0; j<n+1; j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
//输出:
n == 8
i\j
0
1
2
3
4
5
6
7
0
1
循环赛问题分析与C语言代码-分治法
问题描述:设有n个运动员要进行网球循环赛。
设计一个满足以下要求的比赛日程表:(1)每个选手必须与其他n-1个选手各赛一次;(2)每个选手一天只能赛一次;(3)当n是偶数时,循环赛进行n-1天。
当n是奇数时,循环赛进行n天。
分析过程:这个问题的解搜索空间是一个n的全排列。
要求的解是其中的n个排列,满足条件:第1列n个元素值按增序排列;每行每列没有相同的数。
也是一个幻方(除对角线的和不作要求)的问题。
1.n=11)2. n=2(表2)3.n=3,(1) 添加一个虚拟选手4#,构成n+1=4(2) 4/2=2,分两组,每组各自安排(1 2),(3 4)(3)每组跟另一组分别比赛(拷贝)这是四个人比赛的安排(4)把虚选手置为0(表4)3人赛程这是三个人比赛的安排4. n=4, 见表35. n=5, (1)加一个虚选手,n+1=6。
安排好6个人的比赛后,把第6个人用0表示即得5人的。
(2) 分成两组(1 2 3) (4 5 6),各3名选手(3) 依照表4,安排第1组;按表5安排第2组(除0元素外,都加3)(表5)(4) 把表5排于表4下方(5) 把同一天都有空的两组安排在一起比赛(按这种安排,肯定每天只有一对空组,?)。
(6) 第一组的(1 2 3)和第2组的(4 5 6)分别比赛。
但是由于(1,4), (2, 5), (3 6)已经比赛过了,所以在后面的安排中不能再安排他们比赛。
1 2 34 5 6首先,1#只能和5#或6#比赛。
(a)若1#-5#,由于3#和6#已经比赛过,所以只能安排: 2#-6#,3#-4#(b)若1#-6#,由于2#和5#已经比赛过,只能安排:2#-4#,3#-5#这样安排后前三行的后两列,后三行的后两列由上面的三行来定:表8就是6名选手的比赛日程安排。
将其中的6号作为虚拟选手,把6换成0,即得5名选手的赛程安排表:(表9)5人赛程6 n=6,见表8。
7 n=7, 添加1,n+1=8。
赛程表安排--基于循环双链表
赛程安排(赖晓晖:如有错误请大家批评指出,谢谢)大概题意:设有n=2K 支球队,进行n-1天的比赛,每个球队必须跟其他球队都进行比赛,且每天只跟一个球队比赛,(还有一种情况是奇数支球队,这种情况就得n 天才能比完,相信也不难,改一下代码就可以了,具体情况是每天都剩下一支不同的球队不进行比赛) 在此我用多边形法做的具体如下设有(4个球队):3第一天:(1,4)(3,2)13 2第二天:(2,4)(3,1)13 2第三天:(3,4)(1,2)如此用多边形进行安排即可:代码如下:#include<iostream.h>#include<malloc.h>int i,n;typedef struct node//定义链表类型{int data;struct node *next,*prior;}dlinklist;void createlist(dlinklist *&l,int n)//创建循环双链表(用尾插入法){dlinklist *s,*r;l=(dlinklist*)malloc(sizeof(dlinklist));l->data =1;r=l;for(i=2;i<n;i++)4 4s=(dlinklist*)malloc(sizeof(dlinklist));s->data =i;r->next =s;s->prior =r;r=s;}r->next =l;l->prior =r;}void shuchu(dlinklist *&q)//输出具体安排{dlinklist *r=q->prior,*p=q ;cout<<i<<"-->"<<n<<endl;while(p!=r){cout<<p ->data <<"-->"<<r->prior->data <<endl;p=p->next ;r=r->prior ;}}void anpai(dlinklist *l)//只要用来控制P指针指向下一个位置{dlinklist *p=l->next ;for(i=1;i<n;i++){cout<<"第"<<i<<" 天"<<endl;shuchu(p);p=p->next;//}}void destroy(dlinklist *&l)//销毁链表{dlinklist *pre=l, *p=l->next ;while(p!=l){free(pre);pre=p;p=pre->next;free(pre);}void main(){dlinklist *l;cout<<"请输入比赛的球队数(偶数):"<<endl;cin>>n;createlist(l,n);anpai(l);destroy(l);}运行截图:奇数时的代码:#include<iostream.h>#include<malloc.h>int i,n;typedef struct node//定义链表类型{int data;struct node *next,*prior;}dlinklist;void createlist(dlinklist *&l,int n)//创建循环双链表(用尾插入法){dlinklist *s,*r;l=(dlinklist*)malloc(sizeof(dlinklist));l->data =1;r=l;for(i=2;i<=n;i++){s=(dlinklist*)malloc(sizeof(dlinklist));s->data =i;r->next =s;s->prior =r;r=s;}r->next =l;l->prior =r;}void shuchu(dlinklist *&q)//输出具体安排{dlinklist *r=q->prior,*p=q->next;while(p!=r){cout<<p ->data <<"-->"<<r->data <<endl;p=p->next ;r=r->prior ;}}void anpai(dlinklist *l)//只要用来控制P指针指向下一个位置{dlinklist *p=l;for(i=1;i<=n;i++){cout<<"第"<<i<<" 天"<<endl;shuchu(p);p=p->next;//}}void destroy(dlinklist *&l)//销毁链表{dlinklist *pre=l, *p=l->next ;while(p!=l){free(pre);pre=p;p=pre->next;}free(pre);}void main(){dlinklist *l;cout<<"请输入比赛的球队数(奇数):"<<endl;cin>>n;createlist(l,n);anpai(l);destroy(l);}运行截图:。
要求:编写程序,用分治法求解循环赛日程表。
要求:编写程序,用分治法求解循环赛日程表。
一、实验目的与要求1、掌握网球循环赛日程表的算法;2、初步掌握分治算法二、实验题:问题描述:有n=2^k个运动员要进行循环赛。
现要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其他n-1个选手各赛一次(2)每个选手一天只能赛一次(3)循环赛一共进行n-1天三、实验代码#include <stdio.h>#include <stdlib.h>#define MAX 1024int a[MAX][MAX];void Copy(int tox, int toy, int fromx, int fromy, int n){ int i, j;for (i=0; i<n; i++){ for (j=0; j<n; j++){ a[tox + i][toy + j] = a[fromx + i][fromy + j];}}}void Table(int k, int a[][MAX]){ int i, n = 1 << k;for (i=0; i<n; i++){ a[0][i] = i + 1;}for (int r=1; r<n; r<<=1){ for (i=0; i<n; i+=2*r){ Copy(r, i + r, 0, i, r);Copy(r, i, 0, i + r, r);}}}void Out(int a[][MAX], int n){ int i, j;for (i=0; i<n; i++){ for (j=0; j<n; j++){ printf("%3d", a[i][j]);} printf("\n");} printf("\n");}int main(){ int i;for (i=0; i<5; i++){ int len = 1 << i;Table(i, a);Out(a, len);} return 0;}四、实验结果。
循环赛日程表
第一天
1号 2
第二天
3
第三天
4
2号 1
4
3
3号 4
1
2
4号 3
2
1
n=4
void Table(int k)
{
if(k == 2)//只有两个人的时候,可以很简单安排 { a[0][0] = 2; a[1][0] = 1; } else//如果不是两个人的安排,那由上一层安排推出 { Table(k/2);//处理完上一层安排后,用上一层的安排填补空白处 copyToLB(k/2);//填补左下角 copyToRT(k/2);//填补右上角 copyToRB(k/2);//填补右下角 } }
旋转法
先把n(8)为选手的编号存入一个长度为n(8)的一维数组里
1
2
3
4
5
6
7
8
队
列
枢
头
1场 2场 3场 4场
轴
1天
8-5 4-6 3-7 2-1
2天
8-6 5-7 4-1 3-2
3天
4天
5天
6天
7天
具体实现: for(i=0;i<n-1;i++) //1到n-1号旋转i次 {
printf("第%d天: ",i+1); printf("%d - %d ",a[n-1],a[(zhou+i)%(n-1)]);//最后一个和中轴 for( j=1;j<n/2;j++) {//离中轴距离相等的两个 printf("%d - %d ",a[(zhou-j+i)%(n-1)],a[(zhou+j+i)%(n-1)]); } printf("\n"); }
循环赛日程表问题
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
当n=9/10时,规则同上(n=9时用一位虚拟选手补全)
总结:
观察右上角灰色部分可知:【规则一】:每一行数值从左到右循环递增; 每一列上也是6~10循环递增; 第一行第m+1(下标从0开始)列的值为(m+1)+1,依次向右递增;【规则二】:右下角的块:因为比赛是两两之间进行的,所以右下角由右上角决定。
代码实现
代码实现
运行结果
循环赛日程表
/9
内容简介
问题描述
A
解题思路
B
程序实现
C
知识延伸
D
问题描述:设有n(n = 2k)位选手参加网球循环赛,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天必须比赛一场,不能轮空。每个选手必须与其他n-1个选手各赛一场;每个选手一天只能赛一场。
问题描述
解题思路
采用分治法实现,把一个表格分成4个小表格来处理,每个小表格都是一样的处理方法,只是参数不同。分析过程具体如下:
n=1
n=2
选手
第一天
1
1
2
2
1
n=3
n=4
选手
第一天
第二天
第三天
循环赛问题分析与C语言代码分治法
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.1如果n/2为偶数,左下角为左上角加n/2来得到,然后左下角拷贝到右上角;左上角拷贝到右下角;
6
0
4
5
0
3
2
1
(4)把表5排于表4下方
(表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)把同一天都有空的两组安排在一起比赛(按这种安排,肯定每天只有一对空组,?)。
(表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)已经比赛过了,所以在后面的安排中不能再安排他们比赛。
算法分析思维分析,以循环赛日程表为例
算法分析思维分析,以循环赛⽇程表为例第⼀步:分治法的简单思想在计算机科学中,分治法是⼀种很重要的算法。
字⾯上的解释是“分⽽治之”,就是把⼀个复杂的问题分成两个或更多的相同或相似的⼦问题,再把⼦问题分成更⼩的⼦问题……直到最后⼦问题可以简单的直接求解,原问题的解即⼦问题的解的合并。
这个技巧是很多⾼效算法的基础,如排序算法(,归并排序),傅⽴叶变换()等等。
任何⼀个可以⽤计算机求解的问题所需的计算时间都与其规模有关。
问题的规模越⼩,越容易直接求解,解题所需的计算时间也越少。
例如,对于n个元素的排序问题,当n=1时,不需任何计算。
n=2时,只要作⼀次⽐较即可排好序。
n=3时只要作3次⽐较即可,…。
⽽当n较⼤时,问题就不那么容易处理了。
要想直接解决⼀个规模较⼤的问题,有时是相当困难的。
分治法的设计思想是,将⼀个难以直接解决的⼤问题,分割成⼀些规模较⼩的相同问题,以便各个击破,分⽽治之。
分治策略是:对于⼀个规模为n的问题,若该问题可以容易地解决(⽐如说规模n较⼩)则直接解决,否则将其分解为k个规模较⼩的⼦问题,这些⼦问题互相独⽴且与原问题形式相同,递归地解这些⼦问题,然后将各⼦问题的解合并得到原问题的解。
这种算法设计策略叫做分治法。
第⼆步:分治法的理论基础如果原问题可分割成k个⼦问题,1<k≤n ,且这些⼦问题都可解并可利⽤这些⼦问题的解求出原问题的解,那么这种分治法就是可⾏的。
由分治法产⽣的⼦问题往往是原问题的较⼩模式,这就为使⽤递归技术提供了⽅便。
在这种情况下,反复应⽤分治⼿段,可以使⼦问题与原问题类型⼀致⽽其规模却不断缩⼩,最终使⼦问题缩⼩到很容易直接求出其解。
这⾃然导致递归过程的产⽣。
分治与递归像⼀对孪⽣兄弟,经常同时应⽤在算法设计之中,并由此产⽣许多⾼效算法。
2.1分治法所能解决的问题⼀般具有以下⼏个特征: 1) 该问题的规模缩⼩到⼀定的程度就可以容易地解决 2) 该问题可以分解为若⼲个规模较⼩的相同问题,即该问题具有最优⼦结构性质。