C&C++实现算法习题第一部分—递归分治算法(二)

6 篇文章 0 订阅

六. 循环赛日程表问题

问题描述

       设有n= 2^k个运动员要进行循环赛。现需要一个比赛日程表,要求:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛共进行n-1天。

按此要求可将比赛日程表设计成有n行和n- 1列的表.在表中第i行和第j列处填入第i个选手在第j天所遇到的对手。
日程表如图所示
循环赛日程表1

代码
#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");
    }
}

运行结果

循环赛日程表2

七. 大整数乘法

利用矩阵乘法来解决大整数乘法问题,值得注意的是,需要判断两数相乘后得到的答案是整数还是负数,因为大整数/乘法只用到了绝对值,得不到正负信息

实现代码
#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,合并排序,快速排序见上一篇文章点击跳转

参考文献 《计算机算法设计与分析(第四版)》 王晓东 编著

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值