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