设有n=2^k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能参赛一次;
(3)循环赛在n-1天内结束。
请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行,第j列处填入第i个选手在第j天所遇到的选手。其中1≤i≤n,1≤j≤n-1。8个选手的比赛日程表如下图:
递归法
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
using namespace std;
/*循环赛日程表(递归法)*/
void Copy(int **map,int sr,int sl,int dr,int dl,int k){
for (int i = 0; i < k; i++){
for (int j = 0; j < k; j++){
map[dr+i][dl+j] = map[sr+i][sl+j];
}
}
}
void Table(int **map,int r,int l,int k){
if(1==k)return;
//填充左上角
Table(map,r,l,k/2);
//填充右上角
Table(map,r,l+(k/2),k/2);
//从左上角拷贝到右下角
Copy(map,r,l,r+k/2,l+k/2,k/2);
//从右上角拷贝到左下角
Copy(map,r,l+k/2,r+k/2,l,k/2);
}
int main(){
int k;
cin>>k;//输入运动员的人数
int ** p =new int*[k];
//赛程表初始化
for (int i = 0; i < k; i++){
p[i] = new int[k];
p[0][i] = i+1;
p[i][0] = i+1;
}
Table(p,0,0,k);
cout<<"cycle competetion schedule:"<<endl;
for (int i = 0; i < k; i++){
copy(p[i],p[i]+k,ostream_iterator<int>(cout," "));
cout<<endl;
}
return 0;
}
递推 + 递归
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<stdio.h>
#include<math.h>
using namespace std;
int a[100][100];/*循环赛日程表的全局变量*/
/*是一个copy函数,目的是把以r为长度的正方形范围从点from到点to*/
void copy(int tox,int toy,int fromx,int fromy,int r){
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
a[tox+i][toy+j]=a[fromx+i][fromy+j];
}
/*递归算法*/
void Table_recursion(int a[][100],int r,int l,int k){
if(k==1) /*如果就一个当然就直接返回啦*/
return;
Table_recursion(a,r,l,k/2); /*填充左上角*/
Table_recursion(a,r+(k/2),l,k/2); /*填充左下角*/
copy(r+k/2,l+k/2,r,l,k/2); /*从左上角拷贝到右下角*/
copy(r,l+k/2,r+k/2,l,k/2); /*从左下角拷贝到右上角*/
}
/*非递归算法*/
void Table_recursive(int k){
int n=pow(2,k);
for(int i=0;i<n;i++) /*第一列初始化*/
a[i][0]=i+1;
for(int r=2;r<=n;r*=2) /*如果要填充整个表,要有k趟,每一趟的步长为2^i(i=1,2,...k)*/
for(int i=0;i<n;i+=r){ /*针对某一趟,假设这趟步长为r,则需要复制正方形的边长为r的一半*/
int w=r/2;
copy(i+w,w,i,0,w);
copy(i,w,i+w,0,w);
}
}
void print(int a[][100],int n){/*输出整个表*/
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
cout<<a[i][j]<<" ";
if(j==n-1)
puts("");
}
}
int main(){
int k,n;
cout<<"input the power of 2: k = ";
cin>>k;
n=pow(2,k);
cout<<"this is recursive algorithm"<<endl;
Table_recursive(k);
print(a,n);
for(int i=0;i<n;i++)
a[i][0]=i+1;
puts("");
cout<<"this is recursion algorithm"<<endl;
Table_recursion(a,0,0,n);
print(a,n);
}
递推2
#include<stdio.h>
#include<math.h>
void gametable(int k){
int a[100][100];
int n,temp,i,j,t;
n=2;//k=0两个参赛选手日程可以直接求得
a[1][1]=1;a[1][2]=2;
a[2][1]=2;a[2][2]=1;
//迭代处理,依次处理2^n....2^k个选手的比赛日程
for(t=1;t<k;t++){
temp=n;n=n*2;//填左下角元素
for(i=temp+1;i<=n;i++)
for(j=1;j<=temp;j++)
a[i][j]=a[i-temp][j]+temp;//左下角和左上角元素的对应关系
for(i=1;i<=temp;i++)//将左下角元素抄到右上角
for(j=temp+1;j<=n;j++)
a[i][j]=a[i+temp][(j+temp)%n];
for(i=temp+1;i<=n;i++)//将左上角元素抄到右下角
for(j=temp+1;j<=n;j++)
a[i][j]=a[i-temp][j-temp];
}
printf("number:%d\n\n",n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
printf("%d ",a[i][j]);
if(j==n) printf("\n");
}
}
int main(){
int k;
printf("how many people :input K(K>0):\n");
scanf("%d",&k);
if(k!=0) gametable(k);
return 0;
}
其他递归解法
https://blog.csdn.net/qq_32919451/article/details/80634671
不怕丢人再贴一个自己第一次写的,还没debug出来QAQ
#include <stdio.h>
int f(int i,int j){
int a[9][9]={0};
int k;
for(k=1;k<=8;k++){
a[k][1]=k;
if(k%2==1) a[k][2]=k+1;
else a[k][2]=k-1;
}
while(1){
if(1<=i<=8 && 1<=j<=2) return a[i][j];
if(5<=i<=8 && 5<=j<=8) return f(i-4,j-4);
if(1<=i<=4 && 5<=j<=8) return f(i+4,j-4);
if((3<=i<=4 && 3<=j<=4)||(7<=i<=8 && 3<=i<=4))
return f(i-2,j-2);
if((1<=i<=2 && 3<=j<=4)||(5<=i<=6 && 3<=j<=4))
return f(i+2,j-2);
//if(1<=i<=8 && 1<=j<=2) return a[i][j];
}
}
int main(){
int m,n;
scanf("%d %d",&m,&n);
printf("%d",f(m,n));
return 0;
}
反思分析:
- 不具通用性,规律总结不到位,抄表时复制子表阶数是和输入值k相关的
- 循环赛的表只有队员数为2的k次幂才能画出
- 本题递推与递归最明显的不同:递推以for循环为主,递归则是自己调用自己
- …