算法题实战:计算第K个答案-------摩尔斯电码字典

算法题实战:计算第K个答案—摩尔斯电码字典(杨辉三角+递归)

题目

摩尔斯电码字典
在没有电话的时代,摩尔斯电码是无线电传输领域中的一种常用代码。电码以短信号(短点,o)和长信号(长点,-)的不同组合表示各种文字。例如:o—表示英文字母J,而—表示英文字母M。
假设有一本以n个长点和m(n、m<=100)个短点组成的、包含所有信号的字典。例如:n=m=2,就会包含如下信号。
–oo
-o-o
-oo-
o–o
o-o-
oo–
这些信号已按照字典顺序排列好了。-的ASKII码是45,而o的ASCII码是111。因此,按照字典顺序,-在前,o在后。给定n和m时,编写代码计算出此字典的第k(k<=1,000,000,000,000)个信号。例如:上述字典的第四个信号是o–o。

分析

这道题是求特定组合数,给n个长点和m个短点,按字典序排列好,求第K个信号组合。
数据范围:k<=1,000,000,000,000,使用long long 类型。
首先,用杨辉三角基本算法建立m+n行杨辉三角,通过杨辉三角计算出n个长点和m个短点所有组合的个数。杨辉三角的值就相当于是从 1到n+m的组合数的全排列,后面可以直接用。
通过vector动态开辟m+n*m+n二维数组,因为k<=1,000,000,000,000, 所以数组类型为long long类型。将组合数与杨辉三角联系起来,用f[i][j]=f[i−1][j]+f[i−1][j−1]f[i][j]=f[i−1][j]+f[i−1][j−1]基本原理双重循环计算出m+n行杨辉三角,保存在vector数组中。C(n+m,n-1)就相当于vector数组nums[n+m][n-1]。
取得k值后,比较k与对应组合数C(n+m,n)的大小确定在不在组成信号个数的范围内,超出范围退出,在范围内就调用com函数,来组合排列出所求信号。com函数通过二分法,动态递归写入string s字符串。

算法

分为三步:
1.假设第一个信号是短点-,判断k是否小于等于C(n+m-1,n-1),如果小于第一位就是短点,执行s=s+’-’;否则s=s+’。’,k=k-C(n+m-1,n-1);
2.如果第一位是’-’,递归com(n+m-1,n-1);如果第一位是’。'递归C(n+m-1,n)即重复一二步,直到n=0;
3.当n
=0时结束递归,并判断m值,不等于0就循环写入s,等于0变结束函数。

代码

VS2017

#include<iostream>
#include<string>
#include<vector>
using namespace std;

string s;
vector<vector <_int64> > nums;

void basicYang(int numRows)//基本方法计算杨辉三角 
{
	int i, j;
	for (i = 0; i < numRows; i++)
	{
		nums[i][0] = 1;
		nums[i][i] = 1;
		for (j = 1; j < i; j++)
			nums[i][j] = nums[i - 1][j - 1] + nums[i - 1][j];
	}
}

void Combin(int n, int m, _int64 k)
{
	if (n > 0) {
		if (k <= nums[n+m-1][n-1]) {
			s = s + '-';
			Combin(n - 1, m, k);
		}
		else {
			s = s + 'o';
			k = k - nums[n + m - 1][n - 1];
			Combin(n, m - 1, k);
		}
	}
	else {
		while (m > 0) {
			s = s + 'o';
			m--;
		}
	}
}
int main()
{
	int n, m;//n个长点,m个短点
	_int64 k;
	cin >> n >> m;
	nums.resize(m + n + 1, vector<_int64>(m + n + 1,0));
	basicYang(n + m +1);
	cout << nums[n + m][n] << endl;
	cin >> k;
	if (k <= nums[n + m][n] && k > 0)
	{
		Combin(n, m, k);
		cout << s << endl;
	}
	else {
		cout << "K不在范围内" << endl;
	}
	nums.clear();
	vector<vector <_int64> > num;
	num.swap(nums);
	system("pause");
	return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值