题目:

摩尔斯电码字典
在没有电话的时代,摩尔斯电码是无线电传输领域中的一种常用代码。电码以短信号(短点,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。

代码

#include<iostream>
#include<string>
#include<algorithm>
#include<graphics.h>
#include<stdlib.h>
#include<conio.h>
#include<Windows.h>
using namespace std;
const int maxn = 1e3 + 5;
double pre[maxn][maxn];
//预处理,计算出所有的组合总数
void pre_solve(int n, int m) {
	//字典序:长点在前,短点在后
	for (int i = 1; i <= n; i++)
		pre[i][0] = 1;
	for (int i = 1; i <= m; i++)
		pre[0][i] = 1;
	//dp,利用状态转移方程求出所有组合
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++)
			pre[i][j] = pre[i - 1][j] + pre[i][j - 1];
	}
}
/*
运用递归找出答案
首先,假设第一个是'-',则前半部分有number = pre[n - 1][m]种组合
比较k和number的大小,判断是在前半部分还是后半部分
判断是前半部分还是后半部分
*/
string find_answer(int n, int m, double k) {
	if (k > pre[n][m])
		return "Error !";
	if (n == 0)
		return string(m, 'o');
	if (m == 0)
		return string(n, '-');
	//前半部分递归
	if (k <= pre[n - 1][m])
		return '-' + find_answer(n - 1, m, k);
	//后半部分递归,前半部分没有,所以要在后半部分找第k-number
	return 'o' + find_answer(n, m - 1, (k - pre[n - 1][m]));
}
void solve(int n, int m) {
	double k;
	wchar_t s[10];
	InputBox(s, 10, _T("查看第k和信号,请输入k"));
	HWND hwnd;
	hwnd = GetHWnd();
	k = _ttoi(s);
	string ans;
	ans = find_answer(n, m, k);
	int t = 0;
	char s1[maxn * 2 + 5];
	for (int i = 0; i < ans.length(); i++, t++)
		s1[t] = ans[i];
	s1[t] = '\0';
	cleardevice();
	wchar_t temp[maxn * 2 + 5];
	_stprintf_s(temp, maxn * 2 + 5, _T("%S"), s1);
	int text_si***(1300 / (m + n) + 5, 35);
	RECT r = { 0, 0, 1299, 599 };
	settextstyle(text_size, 0, _T("黑体"));
	drawtext(temp, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	getch();
}
void input(int& n, int& m) {
	wchar_t s1[10];
	InputBox(s1, 10, _T("请输入长点n"));
	HWND hwnd;
	hwnd = GetHWnd();
	n = _ttoi(s1);
	wchar_t s2[10];
	InputBox(s2, 10, _T("请输入短点m"));
	m = _ttoi(s2);
}
void graph_case(int& n, int& m) {
	cleardevice();
	settextstyle(30, 0, _T("楷体"));
	outtextxy(450, 170, _T("1.输入长点和短点的数量"));
	outtextxy(450, 270, _T("2.计算第k个信号"));
	outtextxy(450, 370, _T("3.退出系统"));
	getch();
	wchar_t s[10];
	InputBox(s, 10, _T("请输入要进行的操作"));
	HWND hwnd;
	hwnd = GetHWnd();
	int ch = _ttoi(s);
	if (ch == 1) {
		input(n, m);
		pre_solve(n, m); //进行预处理
	}
	if (ch == 2) {
		if (n == 0 && m == 0) {
			cleardevice();
			RECT r = { 0, 0, 1299, 599 };
			drawtext(_T("错误!请先输入长点和短点的数量"), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
			getch();
		}
		else
			solve(n, m);
	}
	if (ch == 3)
		exit(0);
}
void graph() {
	initgraph(1300, 600);
	setbkcolor(WHITE);
	cleardevice();
	settextcolor(BLACK);
	settextstyle(60, 0, _T("楷体"));
	outtextxy(450, 220, _T("摩尔斯电码字典"));
	settextstyle(30, 0, _T("楷体"));
	outtextxy(550, 320, _T("编写:***"));
	Sleep(1500);
	int n = 0, m = 0;
	while (1)
		graph_case(n, m);
}
int main()
{
	graph();
	return 0;
}

运行效果