六. 循环赛日程表问题
问题描述
设有n= 2^k个运动员要进行循环赛。现需要一个比赛日程表,要求:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛共进行n-1天。
按此要求可将比赛日程表设计成有n行和n- 1列的表.在表中第i行和第j列处填入第i个选手在第j天所遇到的对手。
日程表如图所示
代码
#include<stdio.h>
#include<math.h>
#define N 50
void Table(int k,int array[][N]);
void print(int k,int array[N][N]);
void main()
{
int k;
int array[N][N];
printf("设参赛选手的人数为n(n=2^k),请输入k 的值:");
do
{
scanf("%d",&k);
if(k!=0)
{
Table(k,array);
print(k,array);
}
else
printf("您输入的数据有误,请重新输入");
}while(k!=0);
}
void Table(int k,int array[N][N])//数组下标从1开始
{
int i,j,s,t;
int n=1;
for(i=1;i<=k;i++)
n*=2; //求总人数,刚才输入的是k,计算时候要用到n
for(i=1;i<=n;i++)
array[1][i]=i; //第一行排列数字1-8,初始化第一行
int m=1; //用来控制每一次填表时i行j列的起始填充位置
for(s=1;s<=k;s++) //s指对称赋值的总循环次数,即分成几大步进行制作日程表
{
n/=2;
for(t=1;t<=n;t++) //t指明内部对称赋值的循环次数
for(i=m+1;i<=2*m;i++)
for(j=m+1;j<=2*m;j++)
{
array[i][j+(t-1)*m*2]=array[i-m][j+(t-1)*m*2-m]; //右下角等于左上角的值
array[i][j+(t-1)*m*2-m]=array[i-m][j+(t-1)*m*2]; //左下角等于右上角的值
}
m*=2;
}
}
void print(int k,int array[][N])
{
int i,j;
int num=pow(2,k);
printf("%d人的循环赛日程表如下\n",num);
for(i=1;i<=num;i++) //输出二维数组
{
for(j=1;j<=num;j++)
{
printf("%d\t",array[i][j]);
}
printf("\n");
}
}
运行结果
七. 大整数乘法
利用矩阵乘法来解决大整数乘法问题,值得注意的是,需要判断两数相乘后得到的答案是整数还是负数,因为大整数/乘法只用到了绝对值,得不到正负信息
实现代码
#include <iostream>
#include<cmath>
using namespace std;
#define SIGN(A) ((A > 0) ? 1 : -1)
//2048 4141
//十进制
int mul(int x, int y, int n)
{
int sign = SIGN(x) * SIGN(y);
//判断两数相乘后得到的答案是整数还是负数,因为大整数
//乘法只用到了绝对值,得不到正负信息
x = abs(x); //得到绝对值信息
y = abs(y);
if (x == 0 || y == 0) {
//乘积为0
return 0;
}
else if (n == 1)
{
//用不着分解了,直接乘吧
return sign*x * y;
}
else {
//把x分为两部分
//强制转换因为要递归
int a = (int)x / pow(10, (int)(n / 2)); //取前边半截
int b = x - a * pow(10, n / 2); //后边半截
//把y分为两部分
int c = (int)y / pow(10, (int)(n / 2));
int d = y - c * pow(10, n / 2);
//递归使用
int ac = mul(a, c, n / 2);
int bd = mul(b, d, n / 2);
int abcd = mul((a - b), (d - c), n / 2) + ac + bd;
//返回结果 符号+数值
return sign * (ac * pow(10, n) + abcd * pow(10, (int)(n / 2)) + bd);
}
}
int main()
{
int x, y, n;
cout << "输入x和y:" << endl;
cin >> x >> y;
cout << "输入x和y的位数:" << endl;
cin >> n;
if (n % 2 == 0)
{
cout << mul(x, y, n) << endl;
}
else
{
cout << mul(x, y, n + 1) << endl;
}
return 0;
}
运行结果
八. 棋盘覆盖问题
问题简介
棋盘覆盖问题链接
百度百科上有很详细解释。
实现代码
#include <iostream>
#include <stdio.h>
using namespace std;
//将所有元素都初始化为0
int def[101][101]={0};
static int t=0;
void chess(int a,int b,int aa,int bb,int length){
//a,b为子棋盘左上角坐标,aa,bb为特殊点坐标,length为子棋盘长度
if(length==1){
return;
//已经简化为1*1的方格了
}
t++; //编号
int tem =t;
int l=length/2;
if(aa<a+l && bb<b+l){ //覆盖左上角子棋盘
chess(a,b,aa,bb,l);
}
else{
//用tem号L形骨牌覆盖右下角
def[a+l-1][b+l-1]=tem;
//覆盖该棋盘其余方格
chess(a,b,a+l-1,b+l-1,l);
}
if(aa<a+l && bb>=b+l){//覆盖右上角的子棋盘
chess(a,b+l,aa,bb,l);
}
else{
//覆盖左下角
def[a+l-1][b+l]=tem;
//覆盖其余方格
chess(a,b+l,a+l-1,b+l,l);
}
if(aa>=a+l && bb<b+l){//覆盖左下角的子棋盘
chess(a+l,b,aa,bb,l);
}
else{
//覆盖右上角
def[a+l][b+l-1]=tem;
//覆盖其余方格
chess(a+l,b,a+l,b+l-1,l);
}
if(aa>=a+l && bb>=b+l){//覆盖右下角的子棋盘
chess(a+l,b+l,aa,bb,l);
}
else{
//覆盖左上角
def[a+l][b+l]=tem;
//覆盖其余方格
chess(a+l,b+l,a+l,b+l,l);
}
}
int main(){
int a,b,aa,bb,length,m;
//a,b是子棋盘左上角的行号和列号
//aa,bb是特殊点的行号和列号
cout<<"请输入棋盘的边长:";
cin>>length;
cout<<"请输入特殊点位置";
cin>>aa>>bb;
a=b=1;
m=length;
chess(a,b,aa,bb,length);
for(int i=1;i<=m;i++){ //输出结果
for(int j=1;j<=m;j++){
cout.width(3);
cout<<def[i][j];
if(j==m){
cout<<endl;
}
}
}
}
运行结果
整数划分问题,二分查找,二分法求a^n,合并排序,快速排序见上一篇文章点击跳转
参考文献 《计算机算法设计与分析(第四版)》 王晓东 编著