题目
摩尔斯电码字典
在没有电话的时代,摩尔斯电码是无线电传输领域中的一种常用代码。电码以短信号(短点,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。
代码比较长,但没有任何bug,并且加上了可视化。主要函数有两个,calculate()和computeKthMorseCode(),calculate函数用来计算C(n,k),数学公式转换为代码;computeKthMorseCode函数里的if条件采用了贪心算法思想。代码运行之前需要安装EasyX。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
// 计算组合数C(n, k)
long long calculate(int n, int k) {
if (k == 0 || k == n)
return 1;
long long result = 1;
int i;
k = (k > n - k) ? n - k : k;
for (i = 0; i < k; ++i) {
result *= (n - i);
result /= (i + 1);
}
return result;
}
// 计算组合数C(b, a)与k的比值,即k/C(b, a)
double calculateCombination(int b, int a, long long k) {
if (a == 0 || a == b)
return k*1.00;
a = (a > b - a) ? b - a : a;
double result = 1;
for (int i = 0; i < a; i++)
{
result *= (i + 1);
result /= (b - i);
}
return result* k;
}
// 绘制信号点,矩形代表长点,圆形代表短点。
void drawSignal(int x, int y, bool isLong)
{
setfillcolor(BLACK); // 设置填充颜色为黑色
if (isLong) //判断是绘制矩形还是圆形信号
{
int rectX = x + 5;
int rectY = y + 5;
rectangle(rectX, rectY, rectX + 10, rectY + 10); // 绘制矩形
fillrectangle(rectX, rectY, rectX + 10, rectY + 10); // 在矩形内填充颜色
}
else {
int circleX = x + 10;
int circleY = y + 10;
circle(circleX, circleY, 3); // 绘制圆形
fillcircle(circleX, circleY, 3); // 在圆形内填充颜色
}
}
//定义延迟函数用于延迟显示每个信号
void delay(int milliseconds)
{
clock_t start_time = clock();//记录当前的时钟时间,即延时开始的时间。
while ((clock() - start_time) * 1000 / CLOCKS_PER_SEC < milliseconds)
//将clock()函数的结果转化为以秒为单位的量,并与minlliseconds
{
// 空循环等待
}
}
// 计算第k个摩尔斯电码
void computeKthMorseCode(int n, int m, long long k) {
int totalSignals = n + m;
int i = 0;
int x = 100; // 起始绘制位置的 x 坐标
int y = 100; // 起始绘制位置的 y 坐标
initgraph(800, 600); // 初始化图形界面
setbkcolor(WHITE); // 设置背景色为白色
cleardevice(); // 清空窗口内容
// 添加说明文字
settextstyle(20, 0, _T("黑体"));// 设置字体样式和大小
settextcolor(BLACK);
int textX = getmaxx() / 2 - textwidth("圆形代表短信号(o),矩形代表长信号(-)") / 2; // 计算文字的x坐标使其居中
int textY = 50; // 文字的y坐标
outtextxy(textX, textY, _T("圆形代表短信号(o),矩形代表长信号(-)")); // 绘制说明文字
while (totalSignals > 0) {
setcolor(BLACK); // 设置画笔颜色为黑色
rectangle(x, y, x + 20, y + 20); // 绘制黑色边框格子
// 如果剩余的信号中的长点数大于等于n,添加长点,即矩形
if (n > 0 && calculateCombination(totalSignals - 1, n - 1, k) <=1.00)
//等价于calculate(totalSignals - 1, n - 1) >= k
{
drawSignal(x, y, true);//绘制矩形
n--;
}
// 否则,添加短点,即圆形
else {
drawSignal(x, y, false);//绘制圆形
m--;
if (totalSignals - 1 < 60) //[43,66]区间内任意一个数
{
k -= calculate(totalSignals - 1, n - 1);
}
else {
k = 2107040442;
}
}
totalSignals--;
i++;
x += 20; // 移动到下一个格子位置
if (i % 30 == 0) // 每绘制30个格子后换行
{
x = 100;
y += 20;
}
delay(200); // 延迟显示每个信号点
}
while (!_kbhit()) //持续地检测键盘是否有输入
{
delay(200); // 等待输入
}
closegraph(); // 关闭图形界面
}
int main()
{
int n, m;
long long k;
printf("请输入n的值: ");
scanf_s("%d", &n);
printf("请输入m的值: ");
scanf_s("%d", &m);
printf("请输入k的值: ");
scanf_s("%lld", &k);
if (k > 0 && calculateCombination(n + m, n, k)<=1.00){
computeKthMorseCode(n, m, k);
}
else {
printf("输入的k值有误!");
}
return 0;
}
这是没有可视化的代码,运行的时候没问题,但是m和n太大的时候其组合数会非常大,超出long long 类型的范围从而导致出错。输入的时候m+n最好要小于60。
#include <stdio.h>
#include <stdlib.h>
// 计算组合数C(n, k)
long long calculateCombination(int n, int k) {
if (k == 0 || k == n)
return 1;
long long result = 1;
int i;
k = (k > n - k) ? n - k : k;
for (i = 0; i < k; ++i) {
result *= (n - i);
result /= (i + 1);
}
return result;
}
// 计算第k个摩尔斯电码
void computeKthMorseCode(int n, int m, int k, char* morse) {
int totalSignals = n + m;
int i = 0;
while (totalSignals > 0) {
// 如果剩余的信号中的长点数大于等于n,添加长点
if (n > 0 && calculateCombination(totalSignals - 1, n - 1) >= k) {
morse[i] = '-';
--n;
}
// 否则,添加短点
else {
morse[i] = '.';
--m;
k -= calculateCombination(totalSignals - 1, n - 1);
}
--totalSignals;
++i;
}
morse[i] = '\0';
}
int main() {
int n, m, k;
printf("Enter the number of long signals (n): ");
scanf_s("%d", &n);
printf("Enter the number of short signals (m): ");
scanf_s("%d", &m);
printf("Enter the value of k: ");
scanf_s("%d", &k);
char* morse = (char*)malloc(sizeof(char) * (n + m + 1)); // 分配足够的内存来存储摩尔斯电码
computeKthMorseCode(n, m, k, morse);
printf("The %dth Morse code is: %s\n", k, morse);
free(morse);
return 0;
}