问题描述
Sphere Online Judge (SPOJ) 网站的第14道题目是:“I-Keyboard”,如下所示:
这道题目是说使用手机上的数字小键盘发送短信的话,有些英文字母需要多次按同一个数字键才能输入。比如很常用的字母“s”就需要按四次“7”键才行。我们的任务是写一个程序,在不改变字母的顺序的情况下,将这些字母分配到各个按键上,使用得输入信息的总的按键次数最少。输入信息中各个字母出现的频率是已经给定的。
问题解答
下面就是使用动态规划算法解答的 C 语言源程序:
#include <stdio.h>
#include <string.h>
#define MAX (90 + 1)
static int cost[MAX][MAX], price[MAX][MAX], index[MAX][MAX];
void initialize(int L, int F[])
{
memset(price, 0x40, sizeof(price));
price[0][0] = 0;
for (int i = 1; i <= L; i++)
for (int j = i; j <= L; j++)
cost[i][j] = cost[i][j - 1] + (j - i + 1) * F[j - 1];
}
void compute(int K, int L)
{
for (int i = 1; i <= K; i++)
for (int j = i; j <= L; j++)
for (int n = 1; n <= j - i + 1; n++)
{
int sum = price[i - 1][j - n] + cost[j - n + 1][j];
if (sum <= price[i][j]) price[i][j] = sum, index[i][j] = n;
}
}
void output(int K, int L, char keys[], char letters[])
{
if (K == 0) return;
output(K - 1, L - index[K][L], keys, letters);
printf(\"%c: \",keys[K - 1]);
for (int i = L - index[K][L]; i < L; i++) putchar(letters[i]);
puts(\"\");
}
int main(void)
{
int F[MAX - 1], T;
scanf(\"%d\", &T);
for (int K, L, n = 1; n <= T; n++)
{
char keys[MAX], letters[MAX];
scanf(\"%d%d%s%s\", &K, &L, keys, letters);
for (int i = 0; i < L; i++) scanf(\"%d\", F + i);
initialize(L, F);
compute(K, L);
printf(\"Keypad #%d:n\", n);
output(K, L, keys, letters);
puts(\"\");
}
return 0;
}
假设我们有以下输入:
1
3 9
123
ABCDEFGHI
1
30
10
10
10
31
11
12
9