<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_银河</title><subtitle type="text">SKYIV STUDIO</subtitle><id>http://feed.cnblogs.com/blog/u/13647/rss</id><updated>2012-02-11T06:43:58Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/13647/rss"/><entry><id>http://www.cnblogs.com/skyivben/archive/2012/01/31/2334005.html</id><title type="text">C语言常用数据类型的大小</title><summary type="text">本文讨论C语言常用数据类型的大小。</summary><published>2012-01-31T13:49:00Z</published><updated>2012-01-31T13:49:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2012/01/31/2334005.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2012/01/31/2334005.html"/><content type="html">&lt;p&gt;在C语言中，常用的数据类型的大小是随操作系统和编译器等因素变化的。&lt;/p&gt;&#xD;
&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding-left:5px;padding-right:5px;"&gt;&#xD;
&lt;pre&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; #include &amp;lt;&lt;span style="color: #0000ff;"&gt;float&lt;/span&gt;.h&amp;gt;&lt;br /&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;#define&lt;/span&gt; PR(x) printf("%11s: %2lu bytes\n", #x, (unsigned long)sizeof(x))&lt;br /&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;int&lt;/span&gt; main(&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; {&lt;br /&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt;   PR(size_t);&lt;br /&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; *);&lt;br /&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;char&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;short&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;int&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;long&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;long&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;long&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;float&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt;   PR(&lt;span style="color: #0000ff;"&gt;long&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;double&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt;   printf(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;\n---- DIG -------EPSILON -----------MIN -----------MAX\n&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt;   printf(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt; FLT %3d %-14E %-14E %-14E\n&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;, FLT_DIG, FLT_EPSILON, FLT_MIN, FLT_MAX);&lt;br /&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt;   printf(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt; DBL %3d %-14E %-14E %-14E\n&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;, DBL_DIG, DBL_EPSILON, DBL_MIN, DBL_MAX);&lt;br /&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt;   printf(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;LDBL %3d %-14LE %-14LE %-14LE\n&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;, LDBL_DIG, LDBL_EPSILON, LDBL_MIN, LDBL_MAX);&lt;br /&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt;   printf(&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;---- --- -------------- -------------- --------------\n&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt;   &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; &lt;span style="color: #800080;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; }&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这个程序在 ideone.com 中的运行结果如下所示(&lt;a href="http://ideone.com/jH1dT" target="_blank"&gt;http://ideone.com/jH1dT&lt;/a&gt;)：&lt;/p&gt;&#xD;
&lt;pre &gt;size_t:  4 bytes&#xD;
     void *:  4 bytes&#xD;
       char:  1 bytes&#xD;
      short:  2 bytes&#xD;
        int:  4 bytes&#xD;
       long:  4 bytes&#xD;
  long long:  8 bytes&#xD;
      float:  4 bytes&#xD;
     double:  8 bytes&#xD;
long double: 12 bytes&#xD;
&#xD;
---- DIG -------EPSILON -----------MIN -----------MAX&#xD;
 FLT   6 1.192093E-07   1.175494E-38   3.402823E+38  &#xD;
 DBL  15 2.220446E-16   2.225074E-308  1.797693E+308 &#xD;
LDBL  18 1.084202E-19   3.362103E-4932 1.189731E+4932&#xD;
---- --- -------------- -------------- --------------&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;实际上，这是一个 32-bit 的 linux 操作系统，编译器是 gcc 4.3.4。&lt;/p&gt;&#xD;
&lt;p&gt;这个程序在 openSuSE 12.1 64-bit 操作系统中的运行结果如下所示(编译器是 gcc 4.6.2)：&lt;/p&gt;&#xD;
&lt;pre &gt;size_t:  8 bytes&#xD;
     void *:  8 bytes&#xD;
       char:  1 bytes&#xD;
      short:  2 bytes&#xD;
        int:  4 bytes&#xD;
       long:  8 bytes&#xD;
  long long:  8 bytes&#xD;
      float:  4 bytes&#xD;
     double:  8 bytes&#xD;
long double: 16 bytes&#xD;
&#xD;
---- DIG -------EPSILON -----------MIN -----------MAX&#xD;
 FLT   6 1.192093E-07   1.175494E-38   3.402823E+38&#xD;
 DBL  15 2.220446E-16   2.225074E-308  1.797693E+308&#xD;
LDBL  18 1.084202E-19   3.362103E-4932 1.189731E+4932&#xD;
---- --- -------------- -------------- --------------&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;上述结果中，long double 是 16 bytes 的，但是实际上其范围和精度是和 12 bytes 的是一样的，可能是在 64-bit 操作系统中为了对齐字节边界的考虑吧。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2334005.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2012/01/31/2334005.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/12/04/2276031.html</id><title type="text">【算法】验证哥德巴赫猜想</title><summary type="text">本文使用埃拉托斯特尼筛法和米勒-拉宾素性检验等算法来验证哥德巴赫猜想。</summary><published>2011-12-04T13:36:00Z</published><updated>2011-12-04T13:36:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/12/04/2276031.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/12/04/2276031.html"/><content type="html">&lt;p&gt;&lt;strong&gt;问题来源&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://acm.timus.ru/" target="_blank"&gt;Timus Online Judge&lt;/a&gt;&amp;nbsp;网站上有这么一道题目：&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1356" target="_blank"&gt;1356. Something Easier&lt;/a&gt;。这道题目的输入是一组 &amp;nbsp;2 到 10&lt;sup&gt;9&lt;/sup&gt; 之间整数，对于每个输入的整数，要求用最少个数的素数的和来表示。这道题目的时间限制是 1 秒。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;问题解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我们知道著名的&lt;a href="http://en.wikipedia.org/wiki/Goldbach%27s_conjecture" target="_blank"&gt;哥德巴赫猜想&lt;/a&gt;是：&lt;/p&gt;&#xD;
&lt;pre &gt;任何一个充分大的偶数都可以表示为两个素数之和&lt;/pre&gt;&#xD;
&lt;p&gt;于是我们有以下的 C 语言程序(1356.c)：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1356&#xD;
#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;stdlib.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
#include &amp;lt;time.h&amp;gt;&#xD;
&#xD;
// http://en.wikipedia.org/wiki/Prime_number_theorem&#xD;
#define PRIME_MAX 10000&#xD;
#define PRIME_COUNT 1229&#xD;
&#xD;
typedef unsigned long long U8;&#xD;
typedef char bool;&#xD;
&#xD;
const bool true = 1;&#xD;
const bool false = 0;&#xD;
&#xD;
// http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes&#xD;
bool* getSieve(int max)&#xD;
{&#xD;
  static bool sieve[(PRIME_MAX &amp;gt;&amp;gt; 1) + 1];&#xD;
  int i, j, imax = sqrt(max);&#xD;
  for (i = 3; i &amp;lt;= imax; i += 2)&#xD;
    if (!sieve[i &amp;gt;&amp;gt; 1])&#xD;
      for (j = i * i; j &amp;lt;= max; j += i &amp;lt;&amp;lt; 1) sieve[j &amp;gt;&amp;gt; 1] = true;&#xD;
  return sieve;&#xD;
}&#xD;
&#xD;
int* getPrimes(int max)&#xD;
{&#xD;
  static int primes[PRIME_COUNT + 1];&#xD;
  bool *sieve = getSieve(max);&#xD;
  int i, j = 0;&#xD;
  for (primes[j++] = 2, i = 3; i &amp;lt;= max; i += 2)&#xD;
    if (!sieve[i &amp;gt;&amp;gt; 1]) primes[j++] = i;&#xD;
  return primes;&#xD;
}&#xD;
&#xD;
U8 modMultiply(U8 a, U8 b, U8 m)&#xD;
{&#xD;
  return a * b % m;&#xD;
}&#xD;
&#xD;
U8 modPow(U8 a, U8 b, U8 m)&#xD;
{&#xD;
  U8 v = 1, p;&#xD;
  for (p = a % m; b &amp;gt; 0; b &amp;gt;&amp;gt;= 1, p = modMultiply(p, p, m))&#xD;
    if (b &amp;amp; 1) v = modMultiply(v, p, m);&#xD;
  return v;&#xD;
}&#xD;
&#xD;
bool witness(U8 a, U8 n)&#xD;
{&#xD;
  U8 n1 = n - 1, s2 = n1 &amp;amp; -n1, x = modPow(a, n1 / s2, n);&#xD;
  if (x == 1 || x == n1) return false;&#xD;
  for (; s2 &amp;gt; 1; s2 &amp;gt;&amp;gt;= 1)&#xD;
  {&#xD;
    x = modMultiply(x, x, n);&#xD;
    if (x == 1) return true;&#xD;
    if (x == n1) return false;&#xD;
  }&#xD;
  return true;&#xD;
}&#xD;
&#xD;
U8 random(U8 high)&#xD;
{&#xD;
  // http://www.cppreference.com/wiki/c/other/rand&#xD;
  return (U8)(high * (rand() / (double)RAND_MAX));&#xD;
}&#xD;
&#xD;
// http://en.wikipedia.org/wiki/Miller-Rabin_primality_test&#xD;
// n, an integer to be tested for primality&#xD;
// k, a parameter that determines the accuracy of the test&#xD;
bool probablyPrime(U8 n, int k)&#xD;
{&#xD;
  if (n == 2 || n == 3) return 1;&#xD;
  if (n &amp;lt; 2 || n % 2 == 0) return 0;&#xD;
  while (k-- &amp;gt; 0) if (witness(random(n - 3) + 2, n)) return false;&#xD;
  return true;&#xD;
}&#xD;
&#xD;
bool isPrime(int n)&#xD;
{&#xD;
  return probablyPrime(n, 2);&#xD;
}&#xD;
&#xD;
int outEven(int primes[], int n)&#xD;
{&#xD;
  int i, p, q;&#xD;
  for (i = 0; (p = primes[i]) != 0; i++)&#xD;
    if (isPrime(q = n - p))&#xD;
      return printf("%d %d", p, q);&#xD;
  return printf("error:%d", n);&#xD;
}&#xD;
&#xD;
int main(void)&#xD;
{&#xD;
  int t, n, *primes = getPrimes(PRIME_MAX);&#xD;
  srand(time(NULL));&#xD;
  scanf("%d", &amp;amp;t);&#xD;
  while (t-- &amp;gt; 0)&#xD;
  {&#xD;
    scanf("%d", &amp;amp;n);&#xD;
    if (isPrime(n)) printf("%d", n);&#xD;
    else if ((n &amp;amp; 1) == 0) outEven(primes, n);&#xD;
    else if (isPrime(n - 2)) printf("2 %d", n - 2);&#xD;
    else printf("3 "), outEven(primes, n - 3);&#xD;
    puts("");&#xD;
  }&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;上述程序分析如下：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;根据哥德巴赫猜想，充分大的偶数 n = p + q，这里 p &amp;lt;= q 是素数。我们猜测当 n &amp;lt;= 10&lt;sup&gt;9&lt;/sup&gt; 时，p &amp;lt; 10&lt;sup&gt;4&lt;/sup&gt;。第 8 行就是定义 p 的最大值。&lt;/li&gt;&#xD;
&lt;li&gt;根据&lt;a href="http://en.wikipedia.org/wiki/Prime_number_theorem" target="_blank"&gt;素数定理&lt;/a&gt;，我们知道 10&lt;sup&gt;4&lt;/sup&gt; 以内的素数有 1229 个。第 9 行就是定义程序中要用到的素数的个数。&lt;/li&gt;&#xD;
&lt;li&gt;第 17 到 26 行的 getSieve 函数用&lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" target="_blank"&gt;埃拉托斯特尼筛法&lt;/a&gt;筛选出素数。&lt;/li&gt;&#xD;
&lt;li&gt;第 28 到 36 行的 getPrimes 函数从筛中取出这些素数。&lt;/li&gt;&#xD;
&lt;li&gt;第 38 到 79 行的一系列函数最终是为了 probablyPrime 函数，用于检测素数。请参见我在2010年7月写的随笔：&lt;a href="http://www.cnblogs.com/skyivben/archive/2010/07/10/1775001.html" target="_blank"&gt;【算法】米勒-拉宾素性检验&lt;/a&gt;。&lt;/li&gt;&#xD;
&lt;li&gt;第 81 到 84 行的 isPrime 函数调用 probablyPrime 函数来检测素数。&lt;/li&gt;&#xD;
&lt;li&gt;第 86 到 93 行的 outEven 函数对大于 2 的偶数验证哥德巴赫猜想，即输出一对素数 p 和 q。&lt;/li&gt;&#xD;
&lt;li&gt;第 95 到 110 行是 main 函数。其中：&lt;/li&gt;&#xD;
&lt;li&gt;第 103 行处理 n 是素数的情况，直接输出该素数(包括素数 2，所以 outEven 函数处理的偶数肯定大于 2)。&lt;/li&gt;&#xD;
&lt;li&gt;第 104 行对大于 2 的偶数输出一对素数(通过调用 outEven 函数，强哥德巴赫猜想)。&lt;/li&gt;&#xD;
&lt;li&gt;第 105 行处理大于 5 的奇数能够分解为 2 和另外一个素数的和的情况(注意不要遗漏这个情形!)。&lt;/li&gt;&#xD;
&lt;li&gt;第 106 行处理大于 5 的奇数的其他情况，首先输出一个 3，然后调用 outEven 函数处理偶数 n - 3 (弱哥德巴赫猜想)。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;上述程序在 Timus Online Judge 网站的&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1356&amp;amp;author=66595" target="_blank"&gt;运行时间&lt;/a&gt;是 0.015 秒。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Goldbach%27s_conjecture" target="_blank"&gt;Wikipedia: Goldbach's conjecture&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Prime_number_theorem" target="_blank"&gt;Wikipedia: Prime number theorem&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes" target="_blank"&gt;Wikipedia: Sieve of Eratosthenes&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Miller-Rabin_primality_test" target="_blank"&gt;Wikipedia: Miller&amp;ndash;Rabin primality test&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;li&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2010/07/10/1775001.html" target="_blank"&gt;【算法】米勒-拉宾素性检验&lt;/a&gt;&lt;/li&gt;&#xD;
&lt;/ol&gt;&lt;hr /&gt;&#xD;
&lt;p&gt;更多的 ACM 题的解法请参见：&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html" target="_blank"&gt;Timus 目录&lt;/a&gt;。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2276031.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/12/04/2276031.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/26/2264679.html</id><title type="text">【算法】将正整数表示为平方数之和</title><summary type="text">本文讨论将一个正整数表示为正整数的平方和问题。</summary><published>2011-11-26T15:28:00Z</published><updated>2011-11-26T15:28:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/26/2264679.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/26/2264679.html"/><content type="html">&lt;p&gt;&lt;strong&gt;问题来源&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://acm.timus.ru/" target="_blank"&gt;Timus Online Judge&lt;/a&gt; 网站上有这么一道题目：&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1073" target="_blank"&gt;1073. Square Country&lt;/a&gt;。这道题目的输入是一个不大于 60,000 的正整数，要求计算出该正整数最少能够使用多少个正整数的平方和来表示。这道题目的时间限制是 1 秒。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;问题解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://img30.ddimg.cn/61/8/20350600-1_e.jpg" alt="数论导引" width="500" height="500" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;《&lt;a href="http://book.douban.com/subject/3275412/" target="_blank"&gt;数论导引(第5版)&lt;/a&gt;》([英]G.H.Hardy、E.M.Wright 著，人民邮电出版社，2008年10月第1版)第 320 页有以下定理：&lt;/p&gt;&#xD;
&lt;pre &gt;定理 369(Lagrange 定理): 每个正整数都是四个平方数之和&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;在这个定理中，平方数是指整数(包括零)的平方。所以，我们有以下 C 语言程序(1073.c):&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1073&#xD;
#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
&#xD;
int compute(int n)&#xD;
{&#xD;
  int i, j, k, m = 4;&#xD;
  int i0 = n / 4, i2 = n, j2, k2;&#xD;
  for (i = sqrt(n); i2 &amp;gt; i0; i--)&#xD;
    if ((j2 = n - (i2 = i * i)) == 0) return 1;&#xD;
    else for (j = sqrt(j2); j &amp;gt; 0; j--)&#xD;
      if ((k2 = n - i2 - j * j) == 0) return 2;&#xD;
      else if (k = sqrt(k2), k * k == k2 &amp;amp;&amp;amp; m &amp;gt; 3) m = 3;&#xD;
  return m;&#xD;
}&#xD;
&#xD;
int main(void)&#xD;
{&#xD;
  int n;&#xD;
  scanf("%d", &amp;amp;n);&#xD;
  printf("%d", compute(n));&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;上述程序中：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 7 行设置 m 的初值为 4，代表一个正整数最多只需要四个平方数就可以表示了。&lt;/li&gt;&#xD;
&lt;li&gt;第 9 行开始的主循环决定第一个平方数，如果 n 刚好是平方数(第 10 行)，就直接返回 1。&lt;/li&gt;&#xD;
&lt;li&gt;第 11 行开始的内循环决定第二个平方数，如果这两个数加起来刚好等于 n (第 12 行)，就直接返回 2。&lt;/li&gt;&#xD;
&lt;li&gt;第 13 行检查 n 是否可以表示为三个平方数的和，如果是的话，就更新 m 的值为 3 。注意，此时不能直接返回 3，因为可能在后面的循环中发现 n 可以用两个平方数表示。&lt;/li&gt;&#xD;
&lt;li&gt;第 14 行返回 m 值(只可能是 3 或者 4)作为最后的答案。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;上述程序在 Timus Online Judge 网站的&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1073&amp;amp;author=66595" target="_blank"&gt;运行时间&lt;/a&gt;是 0.015 秒。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;更好的算法&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;上述题目有一个进一步的版本：&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1593" target="_blank"&gt;1593. Square Country. Version 2&lt;/a&gt;，输入改为不大于 10&lt;sup&gt;15&lt;/sup&gt; 的正整数，时间限制还是 1 秒。上一节的程序做以下改动：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 5 行的第 2 个 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 8 和 19 行的 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 20 行的 %d 改为 %lld&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;就可以适用于这道题目，但是&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1593&amp;amp;author=66595" target="_blank"&gt;运行结果&lt;/a&gt;是&amp;ldquo;Time limit exceeded&amp;rdquo;。此时，需要更好的算法。我们有以下 C 语言程序(1593.c)：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1593&#xD;
#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
&#xD;
int compute(long long n)&#xD;
{&#xD;
  int i, k;&#xD;
  long long i2;&#xD;
  while ((n &amp;amp; 3) == 0) n &amp;gt;&amp;gt;= 2;&#xD;
  if ((n &amp;amp; 7) == 7) return 4;&#xD;
  for (i = 8, i2 = 9; i2 &amp;lt;= n; i2 += i += 8)&#xD;
    while (n % i2 == 0) n /= i2;&#xD;
  if (n == 1) return 1;&#xD;
  if ((n &amp;amp; 1) == 0) n &amp;gt;&amp;gt;= 1;&#xD;
  if ((n &amp;amp; 3) == 3) return 3;&#xD;
  for (k = sqrt(n), i = 3; i &amp;lt;= k &amp;amp;&amp;amp; n % i; i += 4) ;&#xD;
  return (i &amp;gt; k) ? 2 : 3;&#xD;
}&#xD;
&#xD;
int main(void)&#xD;
{&#xD;
  long long n;&#xD;
  scanf("%lld", &amp;amp;n);&#xD;
  printf("%d", compute(n));&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;在上述程序中：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 9 行消去 n 的所有值为 4 因数。&lt;/li&gt;&#xD;
&lt;li&gt;第 10 行检测 n 是否为 8m + 7 的形式，如是，直接返回 4 (请参见下节)。&lt;/li&gt;&#xD;
&lt;li&gt;第 11、12 行消去 n 的所有素因子的偶次幂(素因子 2 的偶次幂已经在第 9 行消去了)。&lt;/li&gt;&#xD;
&lt;li&gt;第 11 行中 i2 依次为：3&lt;sup&gt;2&lt;/sup&gt;、5&lt;sup&gt;2&lt;/sup&gt;、7&lt;sup&gt;2&lt;/sup&gt;、...、t&lt;sup&gt;2&lt;/sup&gt;，这是因为 (t + 1)&lt;sup&gt;2&lt;/sup&gt; - (t - 1)&lt;sup&gt;2&lt;/sup&gt; = 4t，每次循环 t 增加 2，所以 i 增加 4 * 2 = 8。&lt;/li&gt;&#xD;
&lt;li&gt;第 13 行，如果 n 等于 1，说明输入是个完全平方数，直接返回 1。&lt;/li&gt;&#xD;
&lt;li&gt;此时，n 的标准分解式中所有的素因子都是一次幂了。&lt;/li&gt;&#xD;
&lt;li&gt;第 14 行消去 n 的素因子 2 (如果有的话)。&lt;/li&gt;&#xD;
&lt;li&gt;第 16 行的循环中 i 从 3 开始，每次递增 4，以检查 n 是否有 4m + 3 形式的因子。&lt;/li&gt;&#xD;
&lt;li&gt;第 15 行和第 17 行根据定理 366 决定答案是两个还是三个平方之和。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;这个程序在 Timus Online Judge 网站的&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1593&amp;amp;author=66595" target="_blank"&gt;运行时间&lt;/a&gt;是 0.828 秒。这道题目的&lt;a href="http://acm.timus.ru/rating.aspx?space=1&amp;amp;num=1593" target="_blank"&gt;最佳运行时间&lt;/a&gt;是 0.031 秒，不知道使用什么算法可以这么快。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;上述算法的原理&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;《数论导引(第5版)》第 329 页说：&lt;/p&gt;&#xD;
&lt;fieldset style="background-color: aliceblue;"&gt;n &amp;ne; 4&lt;sup&gt;a&lt;/sup&gt;(8m + 7) 是 n 可以用三个平方数表示的一个充分必要条件&lt;/fieldset&gt;&#xD;
&lt;p&gt;第 318 页有以下定理：&lt;/p&gt;&#xD;
&lt;pre &gt;定理 366: 一个数 n 是两个平方之和，当且仅当在 n 的标准分解式中，它的所有形如 4m + 3 的素因子都有偶次幂&lt;/pre&gt;&#xD;
&lt;p&gt;我们还有以下定理：&lt;/p&gt;&#xD;
&lt;pre &gt;形如 4m + 3 的整数有形如 4m + 3 的素因子&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;列出平方数&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;前面的 1593.c 程序只能给出答案是几个平方数之和，而对这些平方数是什么一无所知。而 1073.c 程序倒是中规中矩地想要求解这些平方数是什么，但是从 Lagrange 定理得知最多只要四个平方数就够了，所以该程序只求解到三个平方数的情况，其余情况下答案肯定是 4 了。因此，我们将 1073.c 稍做修改，得到 1073b.c 用于列出这些平方数，如下所示：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;stdlib.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
&#xD;
static int a[5];&#xD;
&#xD;
int compute(int n)&#xD;
{&#xD;
  int i, j, k, l, m = 5;&#xD;
  int i0 = n / 4, i2 = n, j2, k2, l2;&#xD;
  for (i = sqrt(n); i2 &amp;gt; i0; i--)&#xD;
    if ((j2 = n - (i2 = i * i)) == 0) return a[0] = i, 1;&#xD;
    else for (j = sqrt(j2); j &amp;gt; 0; j--)&#xD;
      if ((k2 = n - i2 - (j2 = j * j)) == 0) return a[0] = i, a[1] = j, 2;&#xD;
      else for (k = sqrt(k2); k &amp;gt; 0; k--)&#xD;
        if ((l2 = n - i2 - j2 - (k2 = k * k)) == 0 &amp;amp;&amp;amp; m &amp;gt; 3)&#xD;
          a[0] = i, a[1] =  j, a[2] = k, m = 3;&#xD;
        else if (l = sqrt(l2), l * l == l2 &amp;amp;&amp;amp; m &amp;gt; 4)&#xD;
          a[0] = i, a[1] =  j, a[2] = k, a[3] = l, m = 4;&#xD;
  return m;&#xD;
}&#xD;
&#xD;
int main(int args, char* argv[])&#xD;
{&#xD;
  int i, n, start = 1, count = 16, k;&#xD;
  if (args &amp;gt; 1) start = atoi(argv[1]);&#xD;
  if (args &amp;gt; 2) count = atoi(argv[2]);&#xD;
  for (n = start; n &amp;lt; start + count; n++)&#xD;
  {&#xD;
    k = compute(n);&#xD;
    printf("%d:%6d:", k, n);&#xD;
    for (i = 0; i &amp;lt; k; i++) printf(" %d", a[i]);&#xD;
    puts(k &amp;gt; 4 ? " Error!" : "");&#xD;
  }&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;上述程序中：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 5 行的全局静态数组用于记录所求的平方数，数组大小为 5， 而不是 4，是为了防止程序有 bug 时造成数组下标越界(第 32 行)。&lt;/li&gt;&#xD;
&lt;li&gt;第 9 行将 m 的初值从 4 改为 5，用以检测程序是否有 bug。&lt;/li&gt;&#xD;
&lt;li&gt;第 9、10 行增加了变量 l 和 l2 用于计算第四个平方数，并相应增加一层循环(第 15 行)。&lt;/li&gt;&#xD;
&lt;li&gt;第 12、14、17 和 19 行相应记录这些平方数于数组 a 中。&lt;/li&gt;&#xD;
&lt;li&gt;第 33 行在输出时检查程序是否有 bug。如果 k &amp;gt; 4 程序肯定有问题，违反了 Lagrange 定理。当然，k &amp;lt;= 4 并不意味着程序就没有问题了。:)&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;这个程序的运行结果如下所示：&lt;/p&gt;&#xD;
&lt;pre &gt;E:\work&amp;gt; &lt;strong&gt;1073b&lt;/strong&gt;&#xD;
1:     1: 1&#xD;
2:     2: 1 1&#xD;
3:     3: 1 1 1&#xD;
1:     4: 2&#xD;
2:     5: 2 1&#xD;
3:     6: 2 1 1&#xD;
4:     7: 2 1 1 1&#xD;
2:     8: 2 2&#xD;
1:     9: 3&#xD;
2:    10: 3 1&#xD;
3:    11: 3 1 1&#xD;
3:    12: 2 2 2&#xD;
2:    13: 3 2&#xD;
3:    14: 3 2 1&#xD;
4:    15: 3 2 1 1&#xD;
1:    16: 4&#xD;
&#xD;
E:\work&amp;gt; &lt;strong&gt;1073b 100001 9&lt;/strong&gt;&#xD;
3:100001: 316 12 1&#xD;
3:100002: 316 11 5&#xD;
3:100003: 315 27 7&#xD;
3:100004: 316 12 2&#xD;
3:100005: 316 10 7&#xD;
3:100006: 311 57 6&#xD;
4:100007: 315 27 7 2&#xD;
3:100008: 314 34 16&#xD;
2:100009: 315 28&#xD;
&#xD;
E:\work&amp;gt; &lt;strong&gt;1073b 987654&lt;/strong&gt;&#xD;
3:987654: 991 58 47&#xD;
4:987655: 993 39 9 2&#xD;
2:987656: 734 670&#xD;
3:987657: 992 53 28&#xD;
3:987658: 993 40 3&#xD;
3:987659: 991 67 33&#xD;
3:987660: 986 110 58&#xD;
3:987661: 990 75 44&#xD;
3:987662: 993 38 13&#xD;
4:987663: 993 38 13 1&#xD;
2:987664: 992 60&#xD;
3:987665: 993 40 4&#xD;
3:987666: 992 59 11&#xD;
3:987667: 993 33 23&#xD;
3:987668: 992 60 2&#xD;
2:987669: 990 87&#xD;
&#xD;
E:\work&amp;gt;&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;如果不知道 Lagrange 定理，也就是说，假设我们不知道要多少个平方数之和才够的话，这道题目看来只好用动态规划算法来求解了。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;使用递归求解&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;键盘农夫园友在 47 楼的评论中介绍了他的随笔&amp;ldquo;&lt;a href="http://www.cnblogs.com/KBTiller/archive/2011/12/04/2275232.html" target="_blank"&gt;华丽的递归&amp;mdash;&amp;mdash;将正整数表示为平方数之和&lt;/a&gt;&amp;rdquo;。我将该随笔中的 C 语言程序改写如下(1073c.c):&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1073&#xD;
#include &amp;lt;stdio.h&amp;gt;&#xD;
 &#xD;
typedef int bool;&#xD;
 &#xD;
const bool true = 1;&#xD;
const bool false = 0;&#xD;
 &#xD;
bool isSquare(int n, int v, int k)&#xD;
{&#xD;
  return (n &amp;lt; v) ? false : (n == v) ? true : isSquare(n, v + k + 2, k + 2);&#xD;
}&#xD;
 &#xD;
bool isSquareSum(int n, int m, int v, int k)&#xD;
{&#xD;
  if (n &amp;lt; v) return false;&#xD;
  if (m == 1) return isSquare(n, v, k);&#xD;
  return isSquareSum(n - v, m - 1, v, k) ? true : isSquareSum(n, m, v + k + 2, k + 2);&#xD;
}&#xD;
 &#xD;
int compute(int n, int m)&#xD;
{&#xD;
  return isSquareSum(n, m, 1, 1) ? m : compute(n, m + 1);&#xD;
}&#xD;
 &#xD;
int main(void)&#xD;
{&#xD;
  int n;&#xD;
  scanf("%d", &amp;amp;n);&#xD;
  printf("%d", compute(n, 1));&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这个程序本质上和键盘农夫园友的程序是没有区别的。分析如下：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 9 到 12 行的 isSquare 函数判断 n 是否是不小于 v 的完全平方数。其中 k 是用于计算平方数的辅助变量。&lt;/li&gt;&#xD;
&lt;li&gt;第 14 到 19 行的 isSquareSum 函数判断 n 是否是 m 个不小于 v 的平方数之和。其中 k 是用于计算平方数的辅助变量。&lt;/li&gt;&#xD;
&lt;li&gt;第 21 到 24 行的 compute 函数计算正整数 n 最少可以表示为多少个平方数之和。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;上述程序在 Timus Online Judge 网站的&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1073&amp;amp;author=66595" target="_blank"&gt;运行时间&lt;/a&gt;是 0.031 秒，而第一小节中的 1073.c 的运行时间是 0.015 秒。&lt;/p&gt;&#xD;
&lt;p&gt;如果将上述程序作如下改动：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;第 9 行的前两个 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 14 行的第 1 个和第 3 个 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 21 行的第 2 个 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 28 行的 int 改为 long long&lt;/li&gt;&#xD;
&lt;li&gt;第 29 行的 %d 改为 %lld&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;就可以适用于&amp;ldquo;&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1593" target="_blank"&gt;1593. Square Country. Version 2&lt;/a&gt;&amp;rdquo;，但是&lt;a href="http://acm.timus.ru/status.aspx?space=1&amp;amp;num=1593&amp;amp;author=66595" target="_blank"&gt;运行结果&lt;/a&gt;是&amp;ldquo;Crash (stack overflow)&amp;rdquo;。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;更多的 ACM 题的解法请参见：&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html" target="_blank"&gt;Timus 目录&lt;/a&gt;。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2264679.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/26/2264679.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/23/2260748.html</id><title type="text">Timus 1727. Znaika&amp;#39;s Magic Numbers</title><summary type="text">Timus 1727. Znaika's Magic Numbers 要求将指定的正整数分解为一些不同的正整数的和，这些正整数的各位数字和加起来刚好等于指定的正整数。</summary><published>2011-11-23T12:49:00Z</published><updated>2011-11-23T12:49:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/23/2260748.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/23/2260748.html"/><content type="html">&lt;p&gt;&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1727" target="_blank"&gt;Timus 1727. Znaika's Magic Numbers&lt;/a&gt; 要求将指定的正整数分解为一些不同的正整数的和。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;h2 &gt;1727. Znaika's Magic Numbers&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;Time Limit: 0.5 second&lt;br /&gt;Memory Limit: 64 MB&lt;/div&gt;&#xD;
&lt;div id="problem_text"&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;Znaika has many interests. For example, now he is investigating the properties of number sets. Znaika writes down some set consisting of different positive integers (he calls this set a&lt;em&gt;generating&lt;/em&gt;&amp;nbsp;set), calculates the sum of all the written digits, and writes down the result in a special notebook. For example, for a generating set 7, 12, 43, he will write down the number17 = 7 + 1 + 2 + 4 + 3. Znaika is sure that only&amp;nbsp;&lt;em&gt;magic&lt;/em&gt;&amp;nbsp;numbers can appear as a result of this operation.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;Neznaika laughs at Znaika. He thinks that there is a generating set for every number, and he even made a bet with Znaika that he would be able to construct such a set.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;Help Neznaika win the bet and construct a generating set for a given number.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Input&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;The only input line contains an integer&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;(0 &amp;lt;&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;&amp;lt; 10&lt;sup&gt;5&lt;/sup&gt;).&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Output&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;If it is possible to construct a generating set for the number&amp;nbsp;&lt;em&gt;n&lt;/em&gt;, output the number of elements in this set in the first line. In the second line output a space-separated list of these elements. The elements of the set must be different positive integers strictly less than 10&lt;sup&gt;5&lt;/sup&gt;. If there are several generating sets, output any of them. If there are no generating sets, output&amp;nbsp;&amp;minus;1.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Sample&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;table &gt;&lt;colgroup&gt;&lt;col width="350" /&gt;&lt;col width="350" /&gt;&lt;/colgroup&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&lt;th&gt;input&lt;/th&gt;&lt;th&gt;output&lt;/th&gt;&lt;/tr&gt;&#xD;
&lt;tr valign="top"&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre &gt;17&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre &gt;3&#xD;
7 12 43&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;div &gt;&lt;strong&gt;Problem Author:&amp;nbsp;&lt;/strong&gt;Ivan Burmistrov&lt;br /&gt;&lt;strong&gt;Problem Source:&amp;nbsp;&lt;/strong&gt;Ural Regional School Programming Contest 2009&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Tags:&amp;nbsp;&lt;/strong&gt;none&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这道题目要求将一个指定的正整数(小于10&lt;sup&gt;5&lt;/sup&gt;)分解为一些不同的正整数(也必须小于10&lt;sup&gt;5&lt;/sup&gt;)之和，这些正整数的各位数字和加起来刚好等于指定的正整数。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;使用 C# 语言解答如下：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
&#xD;
// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1727&#xD;
static class Timus&#xD;
{&#xD;
  static void Main()&#xD;
  {&#xD;
    int n = int.Parse(Console.ReadLine());&#xD;
    int count = Compute(ref n), tops = count;&#xD;
    for (int i = 0; n &amp;gt; 9; i++, n -= 10) count++;&#xD;
    int tens = count - tops;&#xD;
    Console.WriteLine(count += ((n &amp;gt; 0) ? 1 : 0));&#xD;
    for (int i = 99999; tops-- &amp;gt; 0; i--) Console.Write(i + " ");&#xD;
    while (tens-- &amp;gt; 0) Console.Write("19 28 37 46 ".Substring(tens * 3, 3));&#xD;
    if (n &amp;gt; 0) Console.Write(n);&#xD;
  }&#xD;
  &#xD;
  static int Compute(ref int n)&#xD;
  {&#xD;
    int count = 0;&#xD;
    for (int sum = 45; n &amp;gt;= 45; )&#xD;
    {&#xD;
      n -= sum--;&#xD;
      if (++count % 10 == 0) sum += 9;&#xD;
      if (count % 100 == 0) sum += 9;&#xD;
      if (count % 1000 == 0) sum += 9; &#xD;
    }&#xD;
    return count;&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;分析如下：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;首先从 99999 开始往下倒数，直到 n 小于 45。注意，99999 的各位数字之和刚好等于 45，这也是最大的各位数字之和了。&lt;/li&gt;&#xD;
&lt;li&gt;然后利用 19、28、37、46 这四个各位数字之和刚好为 10 的数字。&lt;/li&gt;&#xD;
&lt;li&gt;最后 n 必然小于 10，如果 n 不为零的话，直接输出 n。&lt;/li&gt;&#xD;
&lt;li&gt;Compute 方法就是执行从 99999 开始往下倒数的过程。其各位数字和是很有规律的，也就是从 45 开始往下递减，每遇到整十、整百、整千再加 9。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;此外，还可以使用随机算法，如下所示：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
using System.Linq;&#xD;
using System.Collections.Generic;&#xD;
&#xD;
// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1727&#xD;
static class Timus&#xD;
{&#xD;
  static void Main()&#xD;
  {&#xD;
    var n = int.Parse(Console.ReadLine());&#xD;
    var set = Compute(ref n);&#xD;
    var count = set.Count;&#xD;
    for (var i = 0; n &amp;gt; 9; i++, n -= 10) count++;&#xD;
    var tens = count - set.Count;&#xD;
    Console.WriteLine(count += ((n &amp;gt; 0) ? 1 : 0));&#xD;
    foreach (var i in set) Console.Write(i + " ");&#xD;
    while (tens-- &amp;gt; 0) Console.Write("19 28 37 46 ".Substring(tens * 3, 3));&#xD;
    if (n &amp;gt; 0) Console.Write(n);&#xD;
    Console.WriteLine();&#xD;
  }&#xD;
  &#xD;
  static HashSet&amp;lt;int&amp;gt; Compute(ref int n)&#xD;
  {&#xD;
    var set = new HashSet&amp;lt;int&amp;gt;();&#xD;
    for (var rand = new Random(); n &amp;gt;= 45; )&#xD;
    {&#xD;
      var k = rand.Next(100, 100000);&#xD;
      if (set.Add(k)) n -= k.ToString().Select(x =&amp;gt; x - '0').Sum();&#xD;
    }&#xD;
    return set;&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这个程序使用 HashSet 保存随机生成的正整数，以便丢弃重复的正整数，以及稍后输出这些正整数。注意第 28 行使用 Select 及 Sum 扩展方法进行各位数字求和。&lt;/p&gt;&#xD;
&lt;p&gt;第一个程序运行时间是 0.14 秒，第二个程序也不慢，运行时间是 0.156 秒。&lt;/p&gt;&#xD;
&lt;p&gt;让我们进行一下测试吧：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
using System.Linq;&#xD;
using System.Diagnostics;&#xD;
&#xD;
static class Tester&#xD;
{&#xD;
  static void Main(string[] args)&#xD;
  {&#xD;
    var n = (args.Length == 0) ? 100000000 : int.Parse(args[0]);&#xD;
    Run(n, DigitsSum1);&#xD;
    Run(n, DigitsSum2);&#xD;
  }&#xD;
  &#xD;
  static void Run(int n, Func&amp;lt;int, int&amp;gt; func)&#xD;
  {&#xD;
    var timer = Stopwatch.StartNew();&#xD;
    long sum = 0;&#xD;
    for (var i = 0; i &amp;lt;= n; i++) sum += func(i);&#xD;
    timer.Stop();&#xD;
    Console.WriteLine("{0} {1:N0} {2:N0}", timer.Elapsed, n, sum);&#xD;
  }&#xD;
  &#xD;
  static int DigitsSum1(this int n)&#xD;
  {&#xD;
    var sum = 0;&#xD;
    for (; n &amp;gt; 0; n /= 10) sum += n % 10;&#xD;
    return sum;&#xD;
  }&#xD;
  &#xD;
  static int DigitsSum2(this int n)&#xD;
  {&#xD;
    return n.ToString().Select(x =&amp;gt; x - '0').Sum();&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这个程序的运行结果如下所示：&lt;/p&gt;&#xD;
&lt;pre &gt;E:\work&amp;gt;tester&#xD;
00:00:20.3631972 100,000,000 3,600,000,001&#xD;
00:00:58.6052102 100,000,000 3,600,000,001&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;看来使用 Linq 进行求和也不会很慢。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html"&gt;返回目录&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2260748.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/23/2260748.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/17/2252800.html</id><title type="text">Timus 1149. Sinus Dances</title><summary type="text">一道简单的 ACM 题，要求输出特定格式的字符串。</summary><published>2011-11-17T08:08:00Z</published><updated>2011-11-17T08:08:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/17/2252800.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/17/2252800.html"/><content type="html">&lt;p&gt;&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1149" target="_blank"&gt;Timus 1149. Sinus Dances&lt;/a&gt; 要求输出特定格式的字符串。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;h2 &gt;1149. Sinus Dances&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;Time Limit: 1.0 second&lt;br /&gt;Memory Limit: 16 MB&lt;/div&gt;&#xD;
&lt;div id="problem_text"&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;Let&amp;nbsp;&lt;em&gt;A&lt;sub&gt;n&lt;/sub&gt;&lt;/em&gt;&amp;nbsp;= sin(1&amp;ndash;sin(2+sin(3&amp;ndash;sin(4+&amp;hellip;sin(&lt;em&gt;n&lt;/em&gt;))&amp;hellip;)&lt;br /&gt;Let&amp;nbsp;&lt;em&gt;S&lt;sub&gt;n&lt;/sub&gt;&lt;/em&gt;&amp;nbsp;= (&amp;hellip;(&lt;em&gt;A&lt;/em&gt;&lt;sub&gt;1&lt;/sub&gt;+&lt;em&gt;n&lt;/em&gt;)&lt;em&gt;A&lt;/em&gt;&lt;sub&gt;2&lt;/sub&gt;+&lt;em&gt;n&lt;/em&gt;&amp;ndash;1)&lt;em&gt;A&lt;/em&gt;&lt;sub&gt;3&lt;/sub&gt;+&amp;hellip;+2)&lt;em&gt;A&lt;sub&gt;n&lt;/sub&gt;&lt;/em&gt;+1&lt;br /&gt;For given&amp;nbsp;&lt;em&gt;N&lt;/em&gt;&amp;nbsp;print&amp;nbsp;&lt;em&gt;S&lt;sub&gt;N&lt;/sub&gt;&lt;/em&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Input&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;One integer&amp;nbsp;&lt;em&gt;N&lt;/em&gt;. 1 &amp;le;&amp;nbsp;&lt;em&gt;N&lt;/em&gt;&amp;nbsp;&amp;le; 200&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Output&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;div &gt;Line containing&amp;nbsp;&lt;em&gt;S&lt;sub&gt;N&lt;/sub&gt;&lt;/em&gt;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;h3 &gt;Sample&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;table &gt;&lt;colgroup&gt;&lt;col width="350" /&gt;&lt;col width="350" /&gt;&lt;/colgroup&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&lt;th&gt;input&lt;/th&gt;&lt;th&gt;output&lt;/th&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre &gt;3&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre &gt;((sin(1)+3)sin(1&amp;ndash;sin(2))+2)sin(1&amp;ndash;sin(2+sin(3)))+1&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;div &gt;&lt;strong&gt;Problem Author:&amp;nbsp;&lt;/strong&gt;Vladimir Gladkov&amp;nbsp;&lt;br /&gt;&lt;strong&gt;Problem Source:&amp;nbsp;&lt;/strong&gt;Ural Collegiate Programming Contest, April 2001, Perm, Test Round&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Tags:&amp;nbsp;&lt;/strong&gt;problem for beginners&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;C # 语言解答如下：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
&#xD;
// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1149&#xD;
static class Timus&#xD;
{&#xD;
  const int MAX = 200;&#xD;
  static char[] msg = "sin()+-".ToCharArray();&#xD;
  static char[] A = new char[MAX * 10];&#xD;
  static char[] S = new char[MAX * 5 * MAX];&#xD;
  &#xD;
  static void Main()&#xD;
  {&#xD;
    Console.WriteLine(S, 0, MakeS(int.Parse(Console.ReadLine())));&#xD;
  }&#xD;
  &#xD;
  static int MakeS(int n)&#xD;
  {&#xD;
    var count = 0;&#xD;
    while (count &amp;lt; n - 1) S[count++] = msg[3];  // '('&#xD;
    for (int k, i = 1; i &amp;lt;= n; i++, count++)&#xD;
    {&#xD;
      var N = (n - i + 1).ToString().ToCharArray();&#xD;
      Array.Copy(A, 0, S, count, k = MakeA(i)); // Ai&#xD;
      S[count += k] = msg[5];                   // '+'&#xD;
      Array.Copy(N, 0, S, ++count, N.Length);   // n - i + 1&#xD;
      S[count += N.Length] = msg[4];            // ')'&#xD;
    }&#xD;
    return --count; // 去掉最后 ')'&#xD;
  }&#xD;
&#xD;
  static int MakeA(int n)&#xD;
  {&#xD;
    var count = 0;&#xD;
    for (var i = 1; i &amp;lt;= n; i++, count++)&#xD;
    {&#xD;
      var N = i.ToString().ToCharArray();&#xD;
      Array.Copy(msg, 0, A, count, 4);                  // "sin("&#xD;
      Array.Copy(N, 0, A, count += 4, N.Length);        // i&#xD;
      A[count += N.Length] = msg[(i % 2 == 0) ? 5 : 6]; // '+' or '-'&#xD;
    }&#xD;
    count--; // 覆盖最后 '+' or '-'&#xD;
    for (var i = 0; i &amp;lt; n; i++) A[count++] = msg[4];    // ')'&#xD;
    return count;&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;这道题目和解答都非常简单，就不解释了。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html"&gt;返回目录&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2252800.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/17/2252800.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/16/2250868.html</id><title type="text">C# I/O 助手类</title><summary type="text">使用 C# 语言实现一个 I/O 助手类 IOHelper。</summary><published>2011-11-16T02:50:00Z</published><updated>2011-11-16T02:50:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/16/2250868.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/16/2250868.html"/><content type="html">&lt;p&gt;在使用 C# 语言解 ACM 题的时候，如果能够有一个 ReadInt32 方法直接从标准输入读取整数比较方便的。下面就是一个 I/O 助手类 IOHelper：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;namespace Skyiv&#xD;
{&#xD;
  using System;&#xD;
  using System.IO;&#xD;
  using System.Text;&#xD;
&#xD;
  sealed class IOHelper : IDisposable&#xD;
  {&#xD;
    static readonly Encoding Encoding = Encoding.ASCII; // or UTF8 ?&#xD;
    static readonly byte[] EOLS = Encoding.GetBytes(Environment.NewLine);&#xD;
    static readonly byte[] BLANKS = { 9, 10, 13, 32 }; // tab,lf,cr,space&#xD;
    static readonly byte EOF = 0; // assume '\0' not in input file&#xD;
    &#xD;
    byte[] buf = new byte[32]; // for Write(int n)&#xD;
    byte[] buffer = new byte[64 * 1024];&#xD;
    int current = 0;&#xD;
    int count = 0;&#xD;
    BinaryReader reader;&#xD;
    BinaryWriter writer;&#xD;
    &#xD;
    public IOHelper()&#xD;
      : this(Console.OpenStandardInput(), Console.OpenStandardOutput())&#xD;
    {}&#xD;
    &#xD;
    public IOHelper(Stream reader, Stream writer)&#xD;
    {&#xD;
      this.reader = new BinaryReader(reader);&#xD;
      this.writer = new BinaryWriter(writer);&#xD;
    }&#xD;
    &#xD;
    byte ReadByte()&#xD;
    {&#xD;
      if (current &amp;gt;= count)&#xD;
      {&#xD;
        count = reader.Read(buffer, current = 0, buffer.Length);&#xD;
        if (count == 0) return EOF;&#xD;
      }&#xD;
      return buffer[current++];&#xD;
    }&#xD;
    &#xD;
    public static byte[] GetBytes(string str)&#xD;
    {&#xD;
      return Encoding.GetBytes(str);&#xD;
    }&#xD;
    &#xD;
    public int ReadInt32()&#xD;
    {&#xD;
      var n = 0;&#xD;
      var ok = false;&#xD;
      for (byte b; (b = ReadByte()) != EOF; )&#xD;
      {&#xD;
        if (Array.IndexOf(BLANKS, b) &amp;gt;= 0)&#xD;
          if (ok) break;&#xD;
          else continue;&#xD;
        n = n * 10 + (b - '0');&#xD;
        ok = true;&#xD;
      }&#xD;
      return n;&#xD;
    }&#xD;
    &#xD;
    public int ReadLine(byte[] buffer)&#xD;
    {&#xD;
      var n = 0;&#xD;
      while (n &amp;lt; buffer.Length)&#xD;
      {&#xD;
        var b = ReadByte();&#xD;
        if (b == EOLS[0])&#xD;
        {&#xD;
          if (EOLS.Length == 2 &amp;amp;&amp;amp; ReadByte() != EOLS[1])&#xD;
            throw new InvalidDataException("Invalid EOL");&#xD;
          break;&#xD;
        }&#xD;
        buffer[n++] = b;&#xD;
      }&#xD;
      return n;&#xD;
    }&#xD;
&#xD;
    public void Write(int n)&#xD;
    {&#xD;
      if (n == 0) { writer.Write((byte)'0'); return; }&#xD;
      var i = buf.Length;&#xD;
      for (; n &amp;gt; 0; n /= 10) buf[--i] = (byte)((n % 10) + '0');&#xD;
      Write(buf, i, buf.Length - i);&#xD;
    }&#xD;
    &#xD;
    public void Write(byte[] buffer, int index, int count)&#xD;
    {&#xD;
      writer.Write(buffer, index, count);&#xD;
    }&#xD;
    &#xD;
    public void Write(string str)&#xD;
    {&#xD;
      var buffer = Encoding.GetBytes(str);&#xD;
      writer.Write(buffer, 0, buffer.Length);&#xD;
    }&#xD;
    &#xD;
    public void WriteSpace()&#xD;
    {&#xD;
      writer.Write(BLANKS, 3, 1);&#xD;
    }&#xD;
    &#xD;
    public void WriteLine()&#xD;
    {&#xD;
      writer.Write(EOLS, 0, EOLS.Length);&#xD;
    }&#xD;
    &#xD;
    public void Dispose()&#xD;
    {&#xD;
      if (reader != null) reader.Close();&#xD;
      if (writer != null) writer.Close();&#xD;
    }&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;此外，IOHelper 类还提供以下方法用于处理字符串：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;public int ReadLine(byte[] buffer)&lt;/li&gt;&#xD;
&lt;li&gt;public void Write(byte[] buffer, int index, int count)&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;类似于 C/C++ 语言，这两个方法仅仅把字符串当作字节数组处理，使用 ASCII 码。而不是象 C# 语言中字符串是使用 Unicode 进行编码。&lt;/p&gt;&#xD;
&lt;p&gt;下面是一个使用示例，题目来源请参见&amp;ldquo;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/09/2243068.html" target="_blank"&gt;I-Keyboard&lt;/a&gt;&amp;rdquo;这篇随笔。&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;namespace Skyiv.Ben.Acm&#xD;
{&#xD;
  using System;&#xD;
&#xD;
  // http://www.spoj.pl/problems/IKEYB/&#xD;
  sealed class Ikeyb&#xD;
  {&#xD;
    const int MAX = 90;&#xD;
    &#xD;
    static int[,] cost = new int[MAX + 1, MAX + 1];&#xD;
    static int[,] price = new int[MAX + 1, MAX + 1];&#xD;
    static int[,] index = new int[MAX + 1, MAX + 1];&#xD;
    static int[] F = new int[MAX];&#xD;
    static byte[] keys = new byte[MAX];&#xD;
    static byte[] letters = new byte[MAX];&#xD;
    static byte[] message1 = IOHelper.GetBytes("Keypad #");&#xD;
    static byte[] message2 = IOHelper.GetBytes(": ");&#xD;
    &#xD;
    static IOHelper helper;&#xD;
&#xD;
    static void Main()&#xD;
    {&#xD;
      using (helper = new IOHelper())&#xD;
      {&#xD;
        var runner = new Ikeyb();&#xD;
        var T = helper.ReadInt32();&#xD;
        for (var n = 1; n &amp;lt;= T; n++) runner.Run(n);&#xD;
      }&#xD;
    }&#xD;
&#xD;
    void Run(int n)&#xD;
    {&#xD;
      var K = helper.ReadInt32();&#xD;
      var L = helper.ReadInt32();&#xD;
      helper.ReadLine(keys);&#xD;
      helper.ReadLine(letters);&#xD;
      for (var i = 0; i &amp;lt; L; i++) F[i] = helper.ReadInt32();&#xD;
      Initialize(K, L);&#xD;
      Compute(K, L);&#xD;
      helper.Write(message1, 0, message1.Length);&#xD;
      helper.Write(n);&#xD;
      helper.Write(message2, 0, 1);&#xD;
      helper.WriteLine();&#xD;
      Output(K, L);&#xD;
      helper.WriteLine();&#xD;
    }&#xD;
    &#xD;
    void Initialize(int K, int L)&#xD;
    {&#xD;
      for (var i = 0; i &amp;lt;= K; i++)&#xD;
        for (var j = 1; j &amp;lt;= L; j++)&#xD;
          price[i, j] = int.MaxValue / 2;&#xD;
      for (var i = 1; i &amp;lt;= L; i++)&#xD;
        for (var j = i; j &amp;lt;= L; j++)&#xD;
          cost[i, j] = cost[i, j - 1] + (j - i + 1) * F[j - 1];&#xD;
    }&#xD;
    &#xD;
    void Compute(int K, int L)&#xD;
    {&#xD;
      for (var i = 1; i &amp;lt;= K; i++)&#xD;
        for (var j = i; j &amp;lt;= L; j++)&#xD;
          for (var n = 1; n &amp;lt;= j - i + 1; n++)&#xD;
          {&#xD;
            var sum = price[i - 1, j - n] + cost[j - n + 1, j];&#xD;
            if (sum &amp;lt;= price[i, j])&#xD;
            {&#xD;
              price[i, j] = sum;&#xD;
              index[i, j] = n;&#xD;
            }&#xD;
          }&#xD;
    }&#xD;
&#xD;
    void Output(int K, int L)&#xD;
    {&#xD;
      if (K == 0) return;&#xD;
      var n = index[K--, L];&#xD;
      Output(K, L - n);&#xD;
      helper.Write(keys, K, 1);&#xD;
      helper.Write(message2, 0, message2.Length);&#xD;
      helper.Write(letters, L - n, n);&#xD;
      helper.WriteLine();&#xD;
    }&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;如果给出以下输入：&lt;/p&gt;&#xD;
&lt;pre &gt;1&#xD;
2 5&#xD;
*#&#xD;
ABCDE&#xD;
1024&#xD;
32768&#xD;
2147483647&#xD;
987&#xD;
654321&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;上述程序将产生以下输出：&lt;/p&gt;&#xD;
&lt;pre &gt;Keypad #1:&#xD;
*: ABCD&#xD;
#: E&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;注意上述输出其实是有问题的，正确的输出应该分为 AB 和 CDE 两组。但是程序本身是没有问题的，而是输入数据有问题。因为原来的题目中限定各个字母出现的频率不能超过 100000。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2250868.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/16/2250868.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/14/2248902.html</id><title type="text">Timus 1837. Isenbaev&amp;#39;s Number</title><summary type="text">本文介绍如何求解 Isenbave 数。</summary><published>2011-11-14T13:10:00Z</published><updated>2011-11-14T13:10:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/14/2248902.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/14/2248902.html"/><content type="html">&lt;p&gt;&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1837" target="_blank"&gt;Timus 1837. Isenbaev's Number&lt;/a&gt; 要求计算 Isenbaev 数。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;1837. Isenbaev's Number&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div&gt;Time Limit: 0.5 second&lt;br /&gt;Memory Limit: 64 MB&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;Vladislav Isenbaev is a two-time champion of Ural, vice champion of TopCoder Open 2009, and absolute champion of ACM ICPC 2009. In the time you will spend reading this problem statement Vladislav would have solved a problem. Maybe, even two&amp;hellip;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;Since Vladislav Isenbaev graduated from the Specialized Educational and Scientific Center at Ural State University, many of the former and present contestants at USU have known him for quite a few years. Some of them are proud to say that they either played in the same team with him or played in the same team with one of his teammates&amp;hellip;&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;Let us define&amp;nbsp;&lt;em&gt;Isenbaev's number&lt;/em&gt;&amp;nbsp;as follows. This number for Vladislav himself is 0. For people who played in the same team with him, the number is 1. For people who weren't his teammates but played in the same team with one or more of his teammates, the number is 2, and so on. Your task is to automate the process of calculating Isenbaev's numbers so that each contestant at USU would know their proximity to the ACM ICPC champion.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;The first line contains the number of teams&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;(1 &amp;le;&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;&amp;le; 100). In each of the following&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;lines you are given the names of the three members of the corresponding team. The names are separated with a space. Each name is a nonempty line consisting of English letters, and its length is at most 20 symbols. The first letter of a name is capital and the other letters are lowercase.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;div&gt;&#xD;
&lt;div&gt;For each contestant mentioned in the input data output a line with their name and Isenbaev's number. If the number is undefined, output &amp;ldquo;undefined&amp;rdquo; instead of it. The contestants must be ordered lexicographically.&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Sample&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;table&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&lt;th&gt;input&lt;/th&gt;&lt;th&gt;output&lt;/th&gt;&lt;/tr&gt;&#xD;
&lt;tr valign="top"&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre&gt;7&#xD;
Isenbaev Oparin Toropov&#xD;
Ayzenshteyn Oparin Samsonov&#xD;
Ayzenshteyn Chevdar Samsonov&#xD;
Fominykh Isenbaev Oparin&#xD;
Dublennykh Fominykh Ivankov&#xD;
Burmistrov Dublennykh Kurpilyanskiy&#xD;
Cormen Leiserson Rivest&#xD;
&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;td&gt;&#xD;
&lt;pre&gt;Ayzenshteyn 2&#xD;
Burmistrov 3&#xD;
Chevdar 3&#xD;
Cormen undefined&#xD;
Dublennykh 2&#xD;
Fominykh 1&#xD;
Isenbaev 0&#xD;
Ivankov 2&#xD;
Kurpilyanskiy 3&#xD;
Leiserson undefined&#xD;
Oparin 1&#xD;
Rivest undefined&#xD;
Samsonov 2&#xD;
Toropov 1&#xD;
&lt;/pre&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;div&gt;&lt;strong&gt;Problem Author:&amp;nbsp;&lt;/strong&gt;folklore&lt;br /&gt;&lt;strong&gt;Problem Source:&amp;nbsp;&lt;/strong&gt;Ural Championship 2011&lt;/div&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Tags:&amp;nbsp;&lt;/strong&gt;graph theory&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这道题目是说俄罗斯乌拉尔大学有一个叫 Isenbaev 的牛人，他是 TopCoder Open 2009 和 ACM IPCP 2009 竞赛的双料冠军。许多人都以和他一同组队参赛为荣。退而其次，和他的队友一同参赛也是很有面子的。我们定义 Isenbaev 数如下：Isenbaev 他自己是 0，他的队友是 1。如果不是 Isenbaev 的队友，而是 Isenbaev 的队友参加的团队的成员，则是 2。以此类推。给出一些参赛队伍的名单，要求计算出这些队伍中每个人的 Isenbaev 数。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;下面就解答这道题目的是 C# 语言源程序：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
using System.Collections.Generic;&#xD;
&#xD;
// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1837&#xD;
static class Timus&#xD;
{&#xD;
  enum State { Initial, Prepare, Ready, Done };&#xD;
&#xD;
  static readonly string VIP = "Isenbaev";&#xD;
  static SortedDictionary&amp;lt;string, int&amp;gt; ranks;&#xD;
  static string[][] teams;&#xD;
  static State[] states;&#xD;
  &#xD;
  static void Main()&#xD;
  {&#xD;
    Initialize();&#xD;
    Compute();&#xD;
    foreach (var kvp in ranks) Console.WriteLine(kvp.Key + " "&#xD;
      + ((kvp.Value &amp;lt; 0) ? "undefined" : kvp.Value.ToString()));&#xD;
  }&#xD;
  &#xD;
  static void Initialize()&#xD;
  {&#xD;
    ranks = new SortedDictionary&amp;lt;string, int&amp;gt;();&#xD;
    teams = new string[int.Parse(Console.ReadLine())][];&#xD;
    states = new State[teams.Length]; // value is: Initial&#xD;
    for (var i = 0; i &amp;lt; teams.Length; i++)&#xD;
      foreach (var name in teams[i] = Console.ReadLine().Split())&#xD;
      {&#xD;
        ranks[name] = (name == VIP) ? 0 : -1;&#xD;
        if (name == VIP) states[i] = State.Ready;&#xD;
      }&#xD;
  }&#xD;
  &#xD;
  static void Compute()&#xD;
  {&#xD;
    for (var rank = 1; ; rank++)&#xD;
    {&#xD;
      var done = true;&#xD;
      for (var i = 0; i &amp;lt; states.Length; i++)&#xD;
        if (states[i] == State.Ready)&#xD;
        {&#xD;
          foreach (var name in teams[i]) Compute(name, rank);&#xD;
          states[i] = State.Done;&#xD;
          done = false;&#xD;
        }&#xD;
      if (done) break;&#xD;
      states.Replace(State.Prepare, State.Ready);&#xD;
    }&#xD;
  }&#xD;
  &#xD;
  static void Compute(string name, int rank)&#xD;
  {&#xD;
    if (ranks[name] &amp;gt;= 0) return;&#xD;
    ranks[name] = rank;&#xD;
    for (var i = 0; i &amp;lt; states.Length; i++)&#xD;
      if (states[i] == State.Initial)&#xD;
        foreach (var name2 in teams[i])&#xD;
          if (name2 == name) states[i] = State.Prepare;&#xD;
  }&#xD;
  &#xD;
  static void Replace&amp;lt;T&amp;gt;(this IList&amp;lt;T&amp;gt; c, T a, T b)&#xD;
  {&#xD;
    for (var i = 0; i &amp;lt; c.Count; i++)&#xD;
      if (EqualityComparer&amp;lt;T&amp;gt;.Default.Equals(c[i], a)) c[i] = b;&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;上述程序按照 Isenbave 数从小到大层次递进求解，分析如下：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;line 10: 静态字段 ranks 表示各人的 Isenbave 数，其类型是 SortedDictionay，键就是人的姓名，值是 Isenbave 数。&lt;/li&gt;&#xD;
&lt;li&gt;line 11: 静态字段 teams 表示各参赛队伍，其类型是二维锯齿形数组。因为每个队伍的人数是不固定的。(题目中每个队伍均为三人，我们的程序不受这个限制)&lt;/li&gt;&#xD;
&lt;li&gt;line 12: 静态字段 states 表示求解过程中各参赛队伍的状态，计有&amp;ldquo;初始、预备、就绪、完毕&amp;rdquo;四种。请参见第 7 行的 State 枚举类型。&lt;/li&gt;&#xD;
&lt;li&gt;line 16 - 19: 首先调用 Initialize 方法读入数据并进行初始化，然后调用 Compute 方法求解，最后输出结果。&lt;/li&gt;&#xD;
&lt;li&gt;line 22 - 33: Initialize 方法。首先初始化上面提到的三个字段，注意 states 数组各元素的值被默认初始化为 State.Initial。然后循环读入各参赛队伍的数据，并且根据读入的人员是否为 Isenbave 进行相应处理。如果某个参赛队伍中有 Isenbave，该队伍的状态就设置为 State.Ready。&lt;/li&gt;&#xD;
&lt;li&gt;line 35 - 50: Compute 方法。从 1 开始递增 Isenbave 数进行求解，遍历各个参赛队伍，如果某个队伍的状态为 State.Ready 就遍历该队伍中的每个成员，调用下面要讲解的重载的 Compute 方法进行处理，处理后的队伍的状态改为 State.Done。最后，将处理后的状态为 State.Prepare 的队伍的都改为 State.Ready 状态，以便下次循环时继续求解。&lt;/li&gt;&#xD;
&lt;li&gt;line 52 - 60: 重载的 Compute 方法。如果队伍中某人的 Isenbave 数已经求出来了，就什么也不做立即返回。否则，设置他的 Isenbave 数。然后遍历状态为 State.Initial 的队伍，如果某人是该队伍的成员，则这个队伍的状态设置为 State.Prepare，以便在下个层次的循环中进行处理。&lt;/li&gt;&#xD;
&lt;li&gt;line 62 - 66: Replace 扩展方法。该方法用于对列表中的特定元素进行替换。可以作为一个小小的工具使用。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&lt;strong&gt;另一种解法&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;使用 List 代替数组的另外一种解法：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
using System.Collections.Generic;&#xD;
&#xD;
// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1837&#xD;
static class Timus&#xD;
{&#xD;
  static readonly string VIP = "Isenbaev";&#xD;
  static SortedDictionary&amp;lt;string, int&amp;gt; ranks;&#xD;
  static List&amp;lt;string[]&amp;gt; initial, prepare, ready;&#xD;
  &#xD;
  static void Main()&#xD;
  {&#xD;
    Initialize();&#xD;
    Compute();&#xD;
    foreach (var kvp in ranks) Console.WriteLine(kvp.Key + " "&#xD;
      + ((kvp.Value &amp;lt; 0) ? "undefined" : kvp.Value.ToString()));&#xD;
  }&#xD;
  &#xD;
  static void Initialize()&#xD;
  {&#xD;
    ranks = new SortedDictionary&amp;lt;string, int&amp;gt;();&#xD;
    initial = new List&amp;lt;string[]&amp;gt;();&#xD;
    ready = new List&amp;lt;string[]&amp;gt;();&#xD;
    for (var i = int.Parse(Console.ReadLine()); i &amp;gt; 0; i--)&#xD;
    {&#xD;
      var team = Console.ReadLine().Split();&#xD;
      var isReady = false;&#xD;
      foreach (var name in team)&#xD;
      {&#xD;
        ranks[name] = (name == VIP) ? 0 : -1;&#xD;
        if (name == VIP) isReady = true;&#xD;
      }&#xD;
      (isReady ? ready : initial).Add(team);&#xD;
    }&#xD;
  }&#xD;
  &#xD;
  static void Compute()&#xD;
  {&#xD;
    for (var rank = 1; ready.Count != 0; rank++, ready = prepare)&#xD;
    {&#xD;
      prepare = new List&amp;lt;string[]&amp;gt;();&#xD;
      foreach (var team in ready)&#xD;
        foreach (var name in team)&#xD;
          Compute(name, rank);&#xD;
    }&#xD;
  }&#xD;
  &#xD;
  static void Compute(string name, int rank)&#xD;
  {&#xD;
    if (ranks[name] &amp;gt;= 0) return;&#xD;
    ranks[name] = rank;&#xD;
    for (var i = 0; i &amp;lt; initial.Count; i++)&#xD;
      foreach (var name2 in initial[i])&#xD;
      {&#xD;
        if (name2 != name) continue;&#xD;
        prepare.Add(initial[i]);&#xD;
        initial.RemoveAt(i--);&#xD;
        break;&#xD;
      }&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;在这个程序中，取消了二维锯齿数组 teams 和一维数组 states，使用三个 List 代替，即: initial、prepare 和 ready，分别对应原来的 Initial、Prepare 和 Ready &amp;nbsp;状态。而 Done 状态不再需要了，ready 中的队伍处理完毕后，直接将 prepare 改为 ready 进入下一层次的循环。这个程序在大数据量的情况下可能会比第一个程序快一点。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;扩展阅读&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;维基百科中的&amp;ldquo;&lt;a href="http://zh.wikipedia.org/wiki/%E5%9F%83%E5%B0%94%E5%BE%B7%E4%BB%80%E6%95%B0" target="_blank"&gt;埃尔德什数&lt;/a&gt;(&lt;a href="http://en.wikipedia.org/wiki/Erd%C5%91s_number" target="_blank"&gt;Erdős number&lt;/a&gt;)&amp;rdquo;应该是这道题目的背景。与此相关的还有&amp;ldquo;&lt;a href="http://zh.wikipedia.org/wiki/%E5%85%AD%E5%BA%A6%E5%88%86%E9%9A%94%E7%90%86%E8%AE%BA" target="_blank"&gt;六度分隔理论&lt;/a&gt;(&lt;a href="http://en.wikipedia.org/wiki/Small_world_experiment" target="_blank"&gt;Small world experiment&lt;/a&gt;)&amp;rdquo;。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html"&gt;返回目录&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2248902.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/14/2248902.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/09/2243068.html</id><title type="text">I-Keyboard</title><summary type="text">本文讨论使用动态规划算法求解手机数字键盘上字母分配的最优方案。</summary><published>2011-11-09T14:46:00Z</published><updated>2011-11-09T14:46:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/09/2243068.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/09/2243068.html"/><content type="html">&lt;p&gt;&lt;strong&gt;问题描述&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.spoj.pl" target="_blank"&gt;Sphere Online Judge (SPOJ)&lt;/a&gt; 网站的第14道题目是：&amp;ldquo;&lt;a href="http://www.spoj.pl/problems/IKEYB/" target="_blank"&gt;I-Keyboard&lt;/a&gt;&amp;rdquo;，如下所示：&lt;/p&gt;&#xD;
&lt;fieldset style="background-color: aliceblue;"&gt;&#xD;
&lt;p&gt;&lt;strong&gt;SPOJ Problem Set (classical)&lt;br /&gt; 14. I-Keyboard&lt;br /&gt; Problem code: IKEYB&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Most of you have probably tried to type an&amp;nbsp;SMS message on the keypad of a&amp;nbsp;cellular phone. It is sometimes very annoying to write longer messages, because one key must be usually pressed several times to produce a&amp;nbsp;single letter. It is due to a&amp;nbsp;low number of keys on the keypad. Typical phone has twelve keys only (and maybe some other control keys that are not used for typing). Moreover, only eight keys are used for typing 26&amp;nbsp;letters of an&amp;nbsp;English alphabet. The standard assignment of letters on the keypad is shown in the left picture:&lt;/p&gt;&#xD;
&lt;table border="0" align="CENTER"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&#xD;
&lt;table border="1" cellspacing="0" cellpadding="3"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;1&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;2&lt;br /&gt;abc&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;3&lt;br /&gt;def&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;4&lt;br /&gt;ghi&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;5&lt;br /&gt;jkl&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;6&lt;br /&gt;mno&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;7&lt;br /&gt;pqrs&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;8&lt;br /&gt;tuv&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;9&lt;br /&gt;wxyz&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;*&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;0&lt;br /&gt;&lt;em&gt;space&lt;/em&gt;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;#&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td&gt;&#xD;
&lt;table border="1" cellspacing="0" cellpadding="3"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;1&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;2&lt;br /&gt;abcd&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;3&lt;br /&gt;efg&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;4&lt;br /&gt;hijk&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;5&lt;br /&gt;lm&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;6&lt;br /&gt;nopq&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;7&lt;br /&gt;rs&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;8&lt;br /&gt;tuv&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;9&lt;br /&gt;wxyz&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td align="CENTER"&gt;*&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;0&lt;br /&gt;&lt;em&gt;space&lt;/em&gt;&lt;/td&gt;&#xD;
&lt;td align="CENTER"&gt;#&lt;br /&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;p&gt;There are 3 or 4 letters assigned to each key. If you want the first letter of any group, you press that key once. If you want the second letter, you have to press the key twice. For other letters, the key must be pressed three or four times. The authors of the keyboard did not try to optimise the layout for minimal number of keystrokes. Instead, they preferred the even distribution of letters among the keys. Unfortunately, some letters are more frequent than others. Some of these frequent letters are placed on the third or even fourth place on the standard keyboard. For example,&amp;nbsp;&lt;tt&gt;S&lt;/tt&gt;&amp;nbsp;is a&amp;nbsp;very common letter in an&amp;nbsp;English alphabet, and we need four keystrokes to type it. If the assignment of characters was like in the right picture, the keyboard would be much more comfortable for typing average English texts.&lt;/p&gt;&#xD;
&lt;p&gt;ACM have decided to put an&amp;nbsp;optimised version of the keyboard on its new cellular phone. Now they need a&amp;nbsp;computer program that will find an&amp;nbsp;optimal layout for the given letter frequency. We need to preserve alphabetical order of letters, because the user would be confused if the letters were mixed. But we can assign any number of letters to a&amp;nbsp;single key.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;There is a&amp;nbsp;single positive integer&amp;nbsp;&lt;var&gt;T&lt;/var&gt;&amp;nbsp;on the first line of input (equal to about 2000). It stands for the number of test cases to follow. Each test case begins with a&amp;nbsp;line containing two integers&amp;nbsp;&lt;var&gt;K&lt;/var&gt;,&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;(1 &amp;lt;=&amp;nbsp;&lt;var&gt;K&lt;/var&gt;&amp;nbsp;&amp;lt;=&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;&amp;lt;= 90) separated by a&amp;nbsp;single space.&amp;nbsp;&lt;var&gt;K&lt;/var&gt;&amp;nbsp;is the number of keys,&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;is the number of letters to be mapped onto those keys. Then there are two lines. The first one contains exactly&amp;nbsp;&lt;var&gt;K&lt;/var&gt;&amp;nbsp;characters each representing a&amp;nbsp;name of one key. The second line contains exactly&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;characters representing names of letters of an&amp;nbsp;alphabet. Keys and letters are represented by digits, letters (which are case-sensitive), or any punctuation characters (ASCII code between 33 and 126 inclusively). No two keys have the same character, no two letters are the same. However, the name of a&amp;nbsp;letter can be used also as a&amp;nbsp;name for a&amp;nbsp;key.&lt;/p&gt;&#xD;
&lt;p&gt;After those two lines, there are exactly&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;lines each containing exactly one positive integer&amp;nbsp;&lt;var&gt;F&lt;/var&gt;&lt;sub&gt;1&lt;/sub&gt;,&amp;nbsp;&lt;var&gt;F&lt;/var&gt;&lt;sub&gt;2&lt;/sub&gt;, ...&amp;nbsp;&lt;var&gt;F&lt;/var&gt;&lt;sub&gt;&lt;var&gt;L&lt;/var&gt;&lt;/sub&gt;. These numbers determine the frequency of every letter, starting with the first one and continuing with the others sequentially. The higher number means the more common letter. No frequency will be higher than 100000.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Find an&amp;nbsp;optimal keyboard for each test case. Optimal keyboard is such that has the lowest "price" for typing average text. The&amp;nbsp;&lt;em&gt;price&lt;/em&gt;&amp;nbsp;is determined as the sum of the prices of each letter. The price of a&amp;nbsp;letter is a&amp;nbsp;product of the&amp;nbsp;letter frequency (&lt;var&gt;F&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;) and its position on the key. The order of letters cannot be changed, they must be grouped in the given order.&lt;/p&gt;&#xD;
&lt;p&gt;If there are more solutions with the same price, we will try to maximise the number of letters assigned to the last key, then to the one before the last one etc.&lt;/p&gt;&#xD;
&lt;p&gt;More formally, you are to find a&amp;nbsp;sequence&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;1&lt;/sub&gt;,&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;2&lt;/sub&gt;, ...&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;L&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;representing the position of every letter on a&amp;nbsp;particular key. The sequence must meet following conditions:&lt;/p&gt;&#xD;
&lt;div align="left"&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;1&lt;/sub&gt;&amp;nbsp;= 1&lt;/li&gt;&#xD;
&lt;li&gt;for each&amp;nbsp;&lt;var&gt;i&lt;/var&gt;&amp;gt;1, either&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;=&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;-1&lt;/sub&gt;+1 or&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;= 1&lt;/li&gt;&#xD;
&lt;li&gt;there are at most&amp;nbsp;&lt;var&gt;K&lt;/var&gt;&amp;nbsp;numbers&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;such that&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;= 1&lt;/li&gt;&#xD;
&lt;li&gt;the sum of products&amp;nbsp;&lt;var&gt;S&lt;/var&gt;&lt;sub&gt;&lt;var&gt;P&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;= Sum[i=1..l]&amp;nbsp;&lt;var&gt;F&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;.&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;i&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;is minimal&lt;/li&gt;&#xD;
&lt;li&gt;for any other sequence&amp;nbsp;&lt;var&gt;Q&lt;/var&gt;&amp;nbsp;meeting these criteria and with the same sum&amp;nbsp;&lt;var&gt;S&lt;/var&gt;&lt;sub&gt;&lt;var&gt;Q&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;=&amp;nbsp;&lt;var&gt;S&lt;/var&gt;&lt;sub&gt;&lt;var&gt;P&lt;/var&gt;&lt;/sub&gt;, there exists such&lt;var&gt;M&lt;/var&gt;, 1 &amp;lt;=&amp;nbsp;&lt;var&gt;M&lt;/var&gt;&amp;nbsp;&amp;lt;=&amp;nbsp;&lt;var&gt;L&lt;/var&gt;&amp;nbsp;that for any&amp;nbsp;&lt;var&gt;J&lt;/var&gt;,&amp;nbsp;&lt;var&gt;M&lt;/var&gt;&amp;lt;&lt;var&gt;J&lt;/var&gt;&amp;nbsp;&amp;lt;=&amp;nbsp;&lt;var&gt;L&lt;/var&gt;,&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;J&lt;/var&gt;&lt;/sub&gt;&amp;nbsp;=&amp;nbsp;&lt;var&gt;Q&lt;/var&gt;&lt;sub&gt;&lt;var&gt;J&lt;/var&gt;&lt;/sub&gt;, and&amp;nbsp;&lt;var&gt;P&lt;/var&gt;&lt;sub&gt;&lt;var&gt;M&lt;/var&gt;&lt;/sub&gt;&amp;gt;&lt;var&gt;Q&lt;/var&gt;&lt;sub&gt;&lt;var&gt;M&lt;/var&gt;&lt;/sub&gt;.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;The output for every test case must start with a&amp;nbsp;single line saying&amp;nbsp;&lt;tt&gt;Keypad #&lt;/tt&gt;&lt;var&gt;I&lt;/var&gt;&lt;tt&gt;:&lt;/tt&gt;, where&amp;nbsp;&lt;var&gt;I&lt;/var&gt;&amp;nbsp;is a&amp;nbsp;sequential order of the test case, starting with 1. Then there must be exactly&amp;nbsp;&lt;var&gt;K&lt;/var&gt;&amp;nbsp;lines, each representing one letter, in the same order that was used in input. Each line must contain the character representing the key, a&amp;nbsp;colon, one space and a&amp;nbsp;list of letters assigned to that particular key. Letters are not separated from each other.&lt;/p&gt;&#xD;
&lt;p&gt;Print one blank line after each test case, including the last one.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Example&lt;strong&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;strong&gt;Sample Input:&lt;/strong&gt;&#xD;
1&#xD;
8 26&#xD;
23456789&#xD;
ABCDEFGHIJKLMNOPQRSTUVWXYZ&#xD;
3371&#xD;
589&#xD;
1575&#xD;
1614&#xD;
6212&#xD;
971&#xD;
773&#xD;
1904&#xD;
2989&#xD;
123&#xD;
209&#xD;
1588&#xD;
1513&#xD;
2996&#xD;
3269&#xD;
1080&#xD;
121&#xD;
2726&#xD;
3083&#xD;
4368&#xD;
1334&#xD;
518&#xD;
752&#xD;
427&#xD;
733&#xD;
871&#xD;
&lt;strong&gt;Sample Output:&lt;/strong&gt;&#xD;
Keypad #1:&#xD;
2: ABCD&#xD;
3: EFG&#xD;
4: HIJK&#xD;
5: LM&#xD;
6: NOPQ&#xD;
7: RS&#xD;
8: TUV&#xD;
9: WXYZ&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Warning: large Input/Output data, be careful with certain languages&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;table border="0" cellspacing="0" cellpadding="0" align="left"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Added by:&lt;/td&gt;&#xD;
&lt;td&gt;&lt;a href="http://www.spoj.pl/users/adrian" target="_blank"&gt;Adrian Kosowski&lt;/a&gt;&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Date:&lt;/td&gt;&#xD;
&lt;td&gt;2004-05-09&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Time limit:&lt;/td&gt;&#xD;
&lt;td&gt;5s&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Source limit:&lt;/td&gt;&#xD;
&lt;td&gt;50000B&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Languages:&lt;/td&gt;&#xD;
&lt;td&gt;All&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Resource:&lt;/td&gt;&#xD;
&lt;td&gt;ACM Central European Programming Contest, Prague 2000&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;/fieldset&gt;&#xD;
&lt;p&gt;这道题目是说使用手机上的数字小键盘发送短信的话，有些英文字母需要多次按同一个数字键才能输入。比如很常用的字母&amp;ldquo;s&amp;rdquo;就需要按四次&amp;ldquo;7&amp;rdquo;键才行。我们的任务是写一个程序，在不改变字母的顺序的情况下，将这些字母分配到各个按键上，使用得输入信息的总的按键次数最少。输入信息中各个字母出现的频率是已经给定的。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;问题解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;下面就是使用&lt;a href="http://en.wikipedia.org/wiki/Dynamic_programming" target="_blank"&gt;动态规划算法&lt;/a&gt;解答的 C 语言源程序：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#include &amp;lt;stdio.h&amp;gt;&#xD;
#include &amp;lt;string.h&amp;gt;&#xD;
&#xD;
#define MAX (90 + 1)&#xD;
&#xD;
static int cost[MAX][MAX], price[MAX][MAX], index[MAX][MAX];&#xD;
&#xD;
void initialize(int L, int F[])&#xD;
{&#xD;
  memset(price, 0x40, sizeof(price));&#xD;
  price[0][0] = 0;&#xD;
  for (int i = 1; i &amp;lt;= L; i++)&#xD;
    for (int j = i; j &amp;lt;= L; j++)&#xD;
      cost[i][j] = cost[i][j - 1] + (j - i + 1) * F[j - 1];&#xD;
}&#xD;
&#xD;
void compute(int K, int L)&#xD;
{&#xD;
  for (int i = 1; i &amp;lt;= K; i++)&#xD;
    for (int j = i; j &amp;lt;= L; j++)&#xD;
      for (int n = 1; n &amp;lt;= j - i + 1; n++)&#xD;
      {&#xD;
        int sum = price[i - 1][j - n] + cost[j - n + 1][j];&#xD;
        if (sum &amp;lt;= price[i][j]) price[i][j] = sum, index[i][j] = n;&#xD;
      }&#xD;
}&#xD;
&#xD;
void output(int K, int L, char keys[], char letters[])&#xD;
{&#xD;
  if (K == 0) return;&#xD;
  output(K - 1, L - index[K][L], keys, letters);&#xD;
  printf("%c: ",keys[K - 1]);&#xD;
  for (int i = L - index[K][L]; i &amp;lt; L; i++) putchar(letters[i]);&#xD;
  puts("");&#xD;
}&#xD;
&#xD;
int main(void)&#xD;
{&#xD;
  int F[MAX - 1], T;&#xD;
  scanf("%d", &amp;amp;T);&#xD;
  for (int K, L, n = 1; n &amp;lt;= T; n++)&#xD;
  {&#xD;
    char keys[MAX], letters[MAX];&#xD;
    scanf("%d%d%s%s", &amp;amp;K, &amp;amp;L, keys, letters);&#xD;
    for (int i = 0; i &amp;lt; L; i++) scanf("%d", F + i);&#xD;
    initialize(L, F);&#xD;
    compute(K, L);&#xD;
    printf("Keypad #%d:\n", n);&#xD;
    output(K, L, keys, letters);&#xD;
    puts("");&#xD;
  }&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;假设我们有以下输入：&lt;/p&gt;&#xD;
&lt;pre &gt;1&#xD;
3 9&#xD;
123&#xD;
ABCDEFGHI&#xD;
1&#xD;
30&#xD;
10&#xD;
10&#xD;
10&#xD;
31&#xD;
11&#xD;
12&#xD;
9&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;运行该程序将得到以下输出：&lt;/p&gt;&#xD;
&lt;pre &gt;Keypad #1:&#xD;
1: A&#xD;
2: BCDE&#xD;
3: FGHI&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;算法分析&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;使用上一节的输入数据运行该程序，主要的运行状态如下所示：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/skyivben/242150/o_ikeyb.png" alt="I-Keyboard" width="402" height="625" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;上述程序中：&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;K 是按键的个数。L 是要分配到各个按键中的字符的个数。T 是测试案例的个数。一维数组 F 的大小为 L，保存各个字符出现的频率。&lt;/li&gt;&#xD;
&lt;li&gt;cost 是大小为 L x L 的二维数组，cost[i][j] 表示第 i 到第 j 个字符分配到某个按键上的代价，即输入这 j - i + 1 个字符(乘上它们出现的频率)的总的按键次数。注意，主对角线上的值就是各个字符出现的频率。这体现在源程序中 initialize 函数的第 12 到第 14 行。初始化之后，cost 的数组的值就不再改变了。&lt;/li&gt;&#xD;
&lt;li&gt;price 是大小为 K x L 的二维数组，price[i][j] 表示前 j 个字符分配在前 i 个按建上的最小代价。上图中的 A 的值是大约是 INT_MAX 的一半。第一个字符一定是分配在第一个按键上的，而不管第一个字符出现的频率如何(实际上第一个字符的频率可以设置为任何正数，而不影响程序的运行结果)。所以 price[0][0] 初始化设置为 0，而 price 数组的其他值初始化为一个比较大的数。&amp;nbsp;&lt;/li&gt;&#xD;
&lt;li&gt;index 是大小为 K x L 的二维数组，index[K][L] 表示第 K 个(最后一个)按键上分配的字符数，然后往回倒算，index[K - 1][L - index[K][L]] 表示第 K - 1 个按键上分配的字符数，... 一直倒算到第 1 个按键为止。这体现在源程序第 28 到 35 行的 output 函数中，使用递归是为了以正确的顺序输出这些按键。&lt;/li&gt;&#xD;
&lt;li&gt;程序中最关键的是第 17 到第 26 行的 compute 函数。该函数通过三重循环将问题分角为子任务用动态规划算法求解。子任务是求将 j 个字符分配到 i 个按键上的最小代价。&lt;/li&gt;&#xD;
&lt;li&gt;第 19 行：i 从 1 到 K 循环逐步求解。总共有 K 个按键。&lt;/li&gt;&#xD;
&lt;li&gt;第 20 行：j 从 i 到 L 循环逐步求解。总共有 L 个字符，且每个按键至少必须分配一个字符。&lt;/li&gt;&#xD;
&lt;li&gt;第 21 行：n 从 1 到 j - i + 1 逐步求解。注意，这里 n 是指最后一个按键中分配的字符数。&lt;/li&gt;&#xD;
&lt;li&gt;第 23 行：这是最关键的计算最小代价的公式，sum 由两部分组成，第二部分是将第 j - n + 1 到第 j 个字符(总共 n 个)分配到第 i 个按键(也就是该子任务中的最后一个按键)中的最小代价，第一部分就是将该子任务中剩下的 j - n 个字符分配到前 i - 1 个按键中的最小代价。注意，该子任务总共要分配 j 个字符。&lt;/li&gt;&#xD;
&lt;li&gt;第 24 行：如果计算出来的最小代价比原来的小，就更新最小代价数组 price，并同时更新 index 数组，以便将来输出键盘布局。&lt;/li&gt;&#xD;
&lt;li&gt;三重循环完成，表明整个计算任务完成，L 个字符已经分配到 K 个按键中。此时，price[K][L] 表示所求的最小代价，在我们例子中就是 246。&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;注意，这道题目要求在同等代价下将字符尽量分配到后面的按键中，所以第 24 行比较代价时使用&amp;ldquo;&amp;lt;=&amp;rdquo;，以便尽量增加后面按键的字符数。 如果将这个程序第 24 行的&amp;ldquo;&amp;lt;=&amp;rdquo;改为&amp;ldquo;&amp;lt;&amp;rdquo;，则将得到以下输出：&lt;/p&gt;&#xD;
&lt;pre &gt;Keypad #1:&#xD;
1: ABC&#xD;
2: DE&#xD;
3: FGHI&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;此时，策略是在同等代价下将字符尽量分配到前面的按键中。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;英语国家手机数字键盘的最优方案&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;维基百科网站的 &lt;a href="http://en.wikipedia.org/wiki/Letter_frequency" target="_blank"&gt;Letter frequency&lt;/a&gt; 给出了英语中二十六个字母出现的频率，如下表所示：&lt;/p&gt;&#xD;
&lt;div align="left"&gt;&#xD;
&lt;table border="1" cellspacing="0" cellpadding="0"&gt;&#xD;
&lt;thead&gt;&#xD;
&lt;tr&gt;&lt;th&gt;Letter&lt;/th&gt;&lt;th&gt;Frequency&lt;/th&gt;&lt;/tr&gt;&#xD;
&lt;/thead&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;a&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;8.167%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;b&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;1.492%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;c&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.782%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;d&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;4.253%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;e&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;12.702%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;f&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.228%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;g&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.015%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;h&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;6.094%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;i&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;6.966%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;j&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.153%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;k&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.772%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;l&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;4.025%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;m&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.406%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;n&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;6.749%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;o&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;7.507%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;p&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;1.929%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;q&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.095%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;r&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;5.987%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;s&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;6.327%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;t&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;9.056%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;u&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.758%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;v&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.978%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;w&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;2.360%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;x&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.150%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;y&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;1.974%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&lt;strong&gt;z&lt;/strong&gt;&lt;/td&gt;&#xD;
&lt;td&gt;0.074%&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;根据上表设置相应的输入文件：&lt;/p&gt;&#xD;
&lt;pre &gt;1&#xD;
8 26&#xD;
23456789&#xD;
ABCDEFGHIJKLMNOPQRSTUVWXYZ&#xD;
8167&#xD;
1492&#xD;
2782&#xD;
4253&#xD;
12702&#xD;
2228&#xD;
2015&#xD;
6094&#xD;
6966&#xD;
153&#xD;
772&#xD;
4025&#xD;
2406&#xD;
6749&#xD;
7507&#xD;
1929&#xD;
95&#xD;
5987&#xD;
6327&#xD;
9056&#xD;
2758&#xD;
978&#xD;
2360&#xD;
150&#xD;
1974&#xD;
74&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;运行结果如下所示：&lt;/p&gt;&#xD;
&lt;pre &gt;Keypad #1:&#xD;
2: AB&#xD;
3: CD&#xD;
4: EFG&#xD;
5: HIJK&#xD;
6: LM&#xD;
7: NOPQ&#xD;
8: RS&#xD;
9: TUVWXYZ&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;数字&amp;ldquo;9&amp;rdquo;键上居然有七个英文字母，可见最后几个英文字母出现的频率很低。看来在英文国家手机的数字键盘应该如上设置才能够更好地输入信息。当然，我们输入中文又是另外一回事了，用拼音和用五笔输入法，各个字母的频率也是不同的。其实手机向智能化发展，越来越多地使用全键盘了，不再使用数学小键盘。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;更好的算法&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;我的 C 程序在 SPOJ 网站上&lt;a href="http://www.spoj.pl/status/IKEYB,skyivben/" target="_blank"&gt;提交的结果&lt;/a&gt;如下所示：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/skyivben/242150/o_ikeyb2.png" alt="I-Keyboard result" width="726" height="53" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;也就是说我的程序运行时间是 0.57 秒，但是这道题&lt;a href="http://www.spoj.pl/ranks/IKEYB/" target="_blank"&gt;目前最好的运行时间&lt;/a&gt;是 0.21 秒：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/skyivben/242150/o_ikeyb3.png" alt="I-Keyboard ranks" width="726" height="178" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这肯定有更好的算法。有哪位园友知道更好的算法，请在评论中告诉我。谢谢！&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2009/05/18/1459688.html" target="_blank"&gt;算法和数据结构目录&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2243068.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/09/2243068.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/11/02/2231845.html</id><title type="text">Life, the Universe, and Everything</title><summary type="text">介绍 SPOJ 网站的第一道题目，使用 C#、F#、Ruby、Perl、Python、C、C++ 等语言解答，其中 F# 语言解答有三个版本。</summary><published>2011-11-02T01:53:00Z</published><updated>2011-11-02T01:53:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/11/02/2231845.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/11/02/2231845.html"/><content type="html">&lt;p&gt;&lt;strong&gt;问题描述&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.spoj.pl/" target="_blank"&gt;Sphere Online Judge (SPOJ)&lt;/a&gt; 网站的第一道题目是：&amp;ldquo;&lt;a href="http://www.spoj.pl/problems/TEST/" target="_blank"&gt;Life, the Universe, and Everything&lt;/a&gt;&amp;rdquo;，如下所示：&lt;/p&gt;&#xD;
&lt;fieldset style="background-color: aliceblue;"&gt;&#xD;
&lt;p&gt;&lt;strong&gt;SPOJ Problem Set (classical)&lt;br /&gt; 1. Life, the Universe, and Everything&lt;br /&gt; Problem code: TEST&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Your program is to use the brute-force approach in order to&amp;nbsp;&lt;em&gt;find the Answer to Life, the Universe, and Everything.&lt;/em&gt;&amp;nbsp;More precisely... rewrite small numbers from input to output. Stop processing input after reading in the number 42. All numbers at input are integers of one or two digits.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;strong&gt;Input:&lt;/strong&gt;&#xD;
1&#xD;
2&#xD;
88&#xD;
42&#xD;
99&#xD;
&lt;strong&gt;Output:&lt;/strong&gt;&#xD;
1&#xD;
2&#xD;
88&#xD;
&lt;/pre&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Added by:&lt;/td&gt;&#xD;
&lt;td&gt;&lt;a href="http://www.spoj.pl/users/mima" target="_blank"&gt;Michał Małafiejski&lt;/a&gt;&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Date:&lt;/td&gt;&#xD;
&lt;td&gt;2004-05-01&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Time limit:&lt;/td&gt;&#xD;
&lt;td&gt;10s&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Source limit:&lt;/td&gt;&#xD;
&lt;td&gt;50000B&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Languages:&lt;/td&gt;&#xD;
&lt;td&gt;All&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;Resource:&lt;/td&gt;&#xD;
&lt;td&gt;Douglas Adams, &lt;a href="http://en.wikipedia.org/wiki/The_Hitchhiker%27s_Guide_to_the_Galaxy" target="_blank"&gt;The Hitchhiker's Guide to the Galaxy&lt;/a&gt;&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;/fieldset&gt;&#xD;
&lt;p&gt;你要求写一个程序来暴力破解&lt;a href="http://zh.wikipedia.org/wiki/%E7%94%9F%E5%91%BD%E3%80%81%E5%AE%87%E5%AE%99%E4%BB%A5%E5%8F%8A%E4%BB%BB%E4%BD%95%E4%BA%8B%E6%83%85%E7%9A%84%E7%B5%82%E6%A5%B5%E7%AD%94%E6%A1%88" target="_blank"&gt;生命、宇宙及任何事情的终极答案&lt;/a&gt;。准确地说，就是把一些很小的数从输入复制到输出，遇到 42 就停止。输入的所有数都是一位或者两位的整数。这道题目的背景故事来源于英国作家道格拉斯&amp;middot;亚当斯所著的长篇科幻小说《&lt;a href="http://zh.wikipedia.org/zh-cn/%E9%93%B6%E6%B2%B3%E7%B3%BB%E6%BC%AB%E6%B8%B8%E6%8C%87%E5%8D%97_(%E5%B0%8F%E8%AF%B4)" target="_blank"&gt;银河系漫游指南&lt;/a&gt;》，书中说：亚瑟&amp;middot;丹特在马格西亚上被告知，地球其实只是一个实验。原来许多百万年前，老鼠其实是一种超智慧生物，它们建造了一部超级电脑深思，它们问超级电脑，生命、宇宙以及任何事情的终极答案是什么，经过一段长时间的计算，深思告诉老鼠的后人答案是&amp;nbsp;42，深思解释它只能计算出答案是什么，但答案的原因必须由另一部更高智能的电脑才能解释，而该部电脑就是地球。2005年6月四川科学技术出版社出版了《&lt;a href="http://book.douban.com/subject/1394364/" target="_blank"&gt;银河系漫游指南&lt;/a&gt;》，2011年8月上海译文出版社重新出版了这本科幻小说，书名改为《&lt;a href="http://book.douban.com/subject/6265745/" target="_blank"&gt;银河系搭车客指南&lt;/a&gt;》：&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="http://img3.douban.com/lpic/s3696740.jpg" alt="银河系漫游指南" width="297" height="444" /&gt;&lt;img src="http://img3.douban.com/lpic/s6384969.jpg" alt="银河系搭车客指南" width="306" height="435" /&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;问题解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这道题目是 SPOJ 网站的第一道题目，作为入门的测试，以便让用户熟悉在该网站解题的步骤，所以完全没有难度，其 C# 语言解答如下所示：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;using System;&#xD;
&#xD;
// http://www.spoj.pl/problems/TEST/&#xD;
static class Test&#xD;
{&#xD;
  static void Main()&#xD;
  {&#xD;
    for (string s; (s = Console.ReadLine()) != "42"; Console.WriteLine(s)) ;&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;翻译为对应的 F# 语言：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;open System&#xD;
&#xD;
let mutable s = Console.ReadLine()&#xD;
while s &amp;lt;&amp;gt; "42" do&#xD;
  printfn "%s" s&#xD;
  s &amp;lt;- Console.ReadLine()&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;F# 不是纯函数语言，而是多范式的编程语言。上述 F# 程序使用命令范式，而改为函数式编程则如下所示，使用尾递归：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;let rec test() =&#xD;
  let s = System.Console.ReadLine()&#xD;
  if s &amp;lt;&amp;gt; "42" then&#xD;
    printfn "%s" s&#xD;
    test()&#xD;
&#xD;
test()&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;还可以把函数作为参数传递，也就是所谓的高阶函数：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;let rec test readLine =&#xD;
  let s = readLine()&#xD;
  if s &amp;lt;&amp;gt; "42" then&#xD;
    printfn "%s" s&#xD;
    test readLine&#xD;
&#xD;
test System.Console.ReadLine&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;注意上述 F# 程序上最后一行传递的是参数是 Console.ReadLine 函数本身，而不是该函数的返回值。这样才能够不断读取输入行。第一行定义 test 函数时也不用指明形参 readLine 的类型，F# 语言编译器能够根据上下文推断出正确的类型。在 C# 语言中函数是不能直接作为参数传递的，必须使用委托或者 Lambda 表达式。&lt;/p&gt;&#xD;
&lt;p&gt;而 Ruby 语言的解答就非常简单了，只有一句话：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;while (num = gets).to_i != 42 do puts num end&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;Perl 语言的解答也非常简单：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;while (($_ = &amp;lt;&amp;gt;) != 42) { print $_; }&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;下面是 Python 语言的解答：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;n = int(input())&#xD;
while n != 42:&#xD;
  print(n)&#xD;
  n = int(input())&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;Java 语言的解答如下所示：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;import java.io.*;&#xD;
&#xD;
class Test&#xD;
{&#xD;
  public static void main(String[] args) throws java.lang.Exception&#xD;
  {&#xD;
    String s;&#xD;
    BufferedReader r = new BufferedReader(new InputStreamReader(System.in));&#xD;
    while (!(s = r.readLine()).startsWith("42")) System.out.println(s);&#xD;
  }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;当然少不了 C 语言解答：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#include &amp;lt;stdio.h&amp;gt; &#xD;
&#xD;
int main(void)&#xD;
{ &#xD;
  for(int x; scanf("%d",&amp;amp;x) &amp;gt; 0 &amp;amp;&amp;amp; x != 42; printf("%d\n", x)) ; &#xD;
  return 0; &#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;还有 C++ 语言解答：&lt;/p&gt;&#xD;
&lt;div &gt;&#xD;
&lt;pre &gt;#include &amp;lt;iostream&amp;gt;&#xD;
&#xD;
using namespace std;&#xD;
 &#xD;
int main()&#xD;
{&#xD;
  for (int x; cin &amp;gt;&amp;gt; x, x != 42; cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl) ;&#xD;
  return 0;&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;p&gt;&lt;/p&gt;&#xD;
&lt;p&gt;所有以上程序都在 SPOJ 网站&lt;a href="http://www.spoj.pl/status/TEST,skyivben/" target="_blank"&gt;提交通过&lt;/a&gt;。该网站运行在 Linux 操作系统下，支持四十多种编程语言。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;在线集成开发环境&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://ideone.com/" target="_blank"&gt;ideone.com&lt;/a&gt; 是一个&amp;ldquo;Onle IDE &amp;amp; Debugging Tool&amp;rdquo;。她的&lt;a href="http://ideone.com/samples" target="_blank"&gt;范例页面&lt;/a&gt;提供了很多编程语言的示例程序，这些示例程序都是用于解答以上问题的。这个网站和 SPOJ 网站的后台都是&amp;nbsp;&lt;a href="http://sphere-research.com/" target="_blank"&gt;Sphere Research Labs&lt;/a&gt;。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2231845.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/11/02/2231845.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/skyivben/archive/2011/10/30/2229476.html</id><title type="text">Timus 1567. SMS-spam</title><summary type="text">该 ACM 题要求计算手机短信的收费情况。使用 C#、C、C++ 和 F# 四种语言解答。</summary><published>2011-10-30T12:01:00Z</published><updated>2011-10-30T12:01:00Z</updated><author><name>银河</name><uri>http://www.cnblogs.com/skyivben/</uri></author><link rel="alternate" href="http://www.cnblogs.com/skyivben/archive/2011/10/30/2229476.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/skyivben/archive/2011/10/30/2229476.html"/><content type="html">&lt;p&gt;&lt;a href="http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1567" target="_blank"&gt;Timus 1567. SMS-spam&lt;/a&gt; 要求计算手机短信的收费情况。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Timus 1567. SMS-spam&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Time Limit: 1.0 second&lt;br /&gt;Memory Limit: 64 MB&lt;/p&gt;&#xD;
&lt;p&gt;Petr, a student, decided to start his own business. He offers SMS advertising services to the business owners renting offices in the newly built &amp;ldquo;Prisma&amp;rdquo; tower. If an office owner wants to use the service, he devises a slogan and Petr texts it from his personal phone to thousands of Ekaterinburg citizens (he already bought the pirated list of mobile phone numbers). The cost of each slogan sent is a sum of costs of each character typed. Cost of an individual character is determined according to a very simple scheme: each tap at the phone's keyboard costs 1 rouble.&lt;/p&gt;&#xD;
&lt;p&gt;Petr's phone doesn't support sophisticated text input technologies, such as T9, and only the english alphabet can be used.&lt;/p&gt;&#xD;
&lt;table style="color: #000000;" border="1" align="center"&gt;&#xD;
&lt;tbody align="center"&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;1&lt;br /&gt;abc&lt;/td&gt;&#xD;
&lt;td&gt;2&lt;br /&gt;def&lt;/td&gt;&#xD;
&lt;td&gt;3&lt;br /&gt;ghi&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;4&lt;br /&gt;jkl&lt;/td&gt;&#xD;
&lt;td&gt;5&lt;br /&gt;mno&lt;/td&gt;&#xD;
&lt;td&gt;6&lt;br /&gt;pqr&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;7&lt;br /&gt;stu&lt;/td&gt;&#xD;
&lt;td&gt;8&lt;br /&gt;vwx&lt;/td&gt;&#xD;
&lt;td&gt;9&lt;br /&gt;yz&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;&#xD;
&lt;td&gt;0&lt;br /&gt;.,!&lt;/td&gt;&#xD;
&lt;td&gt;#&lt;br /&gt;_&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;p&gt;The &amp;ldquo;&lt;code&gt;_&lt;/code&gt;&amp;rdquo; character in the table denotes whitespace. If you want to, for example, type &amp;ldquo;&lt;code&gt;a&lt;/code&gt;&amp;rdquo;, you need to press the &amp;ldquo;&lt;code&gt;1&lt;/code&gt;&amp;rdquo; button once. To type &amp;ldquo;&lt;code&gt;k&lt;/code&gt;&amp;rdquo;, you press &amp;ldquo;&lt;code&gt;4&lt;/code&gt;&amp;rdquo; twice. To type &amp;ldquo;&lt;code&gt;!&lt;/code&gt;&amp;rdquo;, press &amp;ldquo;&lt;code&gt;0&lt;/code&gt;&amp;rdquo; three times.&lt;/p&gt;&#xD;
&lt;p&gt;Petr has to apply this simple algorithm to calculate the cost of every slogan he sends. However, Petr is a very busy man (and, as a matter of fact, doesn't bother to learn arithmetics, because he's a Philosophy student). You just have to help Petr, you are his best friend after all.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;The single line of input contains the slogan. Slogan consists of words, spaces, commas, full stops and exclamation marks. All the words consist of lowercase english letters. Slogan can't be longer than 1000 characters.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Output a single number representing the cost of the given slogan, according to Petr's pricing.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Sample&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;table style="color: #000000;" border="1"&gt;&#xD;
&lt;tbody&gt;&#xD;
&lt;tr&gt;&lt;th&gt;input&lt;/th&gt;&lt;th&gt;output&lt;/th&gt;&lt;/tr&gt;&#xD;
&lt;tr&gt;&#xD;
&lt;td&gt;pokupaite gvozdi tolko v kompanii gvozdederov i tovarischi!&lt;/td&gt;&#xD;
&lt;td&gt;114&lt;/td&gt;&#xD;
&lt;/tr&gt;&#xD;
&lt;/tbody&gt;&#xD;
&lt;/table&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Problem Author: &lt;/strong&gt;Denis Musin&lt;br /&gt;&lt;strong&gt;Problem Source: &lt;/strong&gt;The XIIth USU Programing Championship, October 6, 2007&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;这道题目是讲俄罗斯一位学生 Petr 的创业故事。Petr 购买了数千个叶卡特琳堡市民的手机号码，以便提供发送垃圾短信服务(想不到俄罗斯也有出售非法的手机号码清单，也有垃圾短信)。Petr 是通过他的手机来发送短信的，按照他的手机键盘(跟我们常见的手机键盘的布局有些不同)，&amp;ldquo;a&amp;rdquo;需要按&amp;ldquo;1&amp;rdquo;键一次，&amp;ldquo;k&amp;rdquo;需要按&amp;ldquo;4&amp;rdquo;键两次，&amp;ldquo;!&amp;rdquo;需要按&amp;ldquo;0&amp;rdquo;键三次。Petr 是按照按键次数来收费的，每一次按键收费一卢布。我们的任务就是写一个程序计算每条短信应该收多少钱。&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;解答&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;下面是 C# 源程序：&lt;/p&gt;&#xD;
&lt;pre &gt;&lt;span style="color: black; font-weight: bold;"&gt;01:  &lt;/span&gt;&lt;span style="color: blue;"&gt;using &lt;/span&gt;System;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;02:  &lt;/span&gt;&lt;span style="color: blue;"&gt;using &lt;/span&gt;System.Collections.Generic;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;03:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;04:  &lt;/span&gt;&lt;span style="color: blue;"&gt;namespace &lt;/span&gt;Skyiv.Ben.Timus&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;05:  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;06:  &lt;/span&gt;  &lt;span style="color: green;"&gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1567&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;07:  &lt;/span&gt;  &lt;/span&gt;&lt;span style="color: blue;"&gt;sealed class &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;T1567&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;08:  &lt;/span&gt;  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;09:  &lt;/span&gt;    &lt;span style="color: blue;"&gt;static void &lt;/span&gt;Main()&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;10:  &lt;/span&gt;    {&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;11:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;var &lt;/span&gt;dict = GetPrice();&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;12:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;var &lt;/span&gt;sum = 0;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;13:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue;"&gt;var &lt;/span&gt;c &lt;span style="color: blue;"&gt;in &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.ReadLine()) sum += dict[c];&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;14:  &lt;/span&gt;      &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(sum);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;15:  &lt;/span&gt;    }&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;16:  &lt;/span&gt;    &#xD;
&lt;span style="color: black; font-weight: bold;"&gt;17:  &lt;/span&gt;    &lt;span style="color: blue;"&gt;static &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;char&lt;/span&gt;, &lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;gt; GetPrice()&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;18:  &lt;/span&gt;    {&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;19:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;var &lt;/span&gt;dict = &lt;span style="color: blue;"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;char&lt;/span&gt;, &lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;gt;();&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;20:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;for &lt;/span&gt;(&lt;span style="color: blue;"&gt;var &lt;/span&gt;i = 0; i &amp;lt; 4; i++) dict.Add(&lt;span style="color: #a31515;"&gt;".,! "&lt;/span&gt;[i], (i % 3) + 1);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;21:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;for &lt;/span&gt;(&lt;span style="color: blue;"&gt;var &lt;/span&gt;i = 0; i &amp;lt; 26; i++) dict.Add((&lt;span style="color: blue;"&gt;char&lt;/span&gt;)(i + &lt;span style="color: #a31515;"&gt;'a'&lt;/span&gt;), (i % 3) + 1);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;22:  &lt;/span&gt;      &lt;span style="color: blue;"&gt;return &lt;/span&gt;dict;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;23:  &lt;/span&gt;    }&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;24:  &lt;/span&gt;  }&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;25:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;p&gt;上述程序首先构造一个不同字符的收费表，然后再计算该收的费用。注意如果输入中出现了不在收费表的字符，该程序将抛出 KeyNotFoundException。但这是ACM题，我们只要按照题意写程序就行，也就是按照契约编程，不用考虑意外的输入。&lt;/p&gt;&#xD;
&lt;p&gt;下面是 C 源程序：&lt;/p&gt;&#xD;
&lt;pre &gt;&lt;span style="color: black; font-weight: bold;"&gt;01:  &lt;/span&gt;&lt;span style="color: green;"&gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1567&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;02:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;03:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;stdio.h&amp;gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;04:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;05:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;int &lt;/span&gt;getPrice(&lt;span style="color: blue;"&gt;char &lt;/span&gt;c)&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;06:  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;07:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;'.' &lt;/span&gt;|| c == &lt;span style="color: #a31515;"&gt;' '&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;1;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;08:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;','&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;2;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;09:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;'!'&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;3;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;10:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;return &lt;/span&gt;1 + (c - &lt;span style="color: #a31515;"&gt;'a'&lt;/span&gt;) % 3;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;11:  &lt;/span&gt;}&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;12:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;13:  &lt;/span&gt;&lt;span style="color: blue;"&gt;int &lt;/span&gt;main()&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;14:  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;15:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;int &lt;/span&gt;i, sum = 0;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;16:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;char &lt;/span&gt;buf[1001];&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;17:  &lt;/span&gt;  gets(buf);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;18:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;for &lt;/span&gt;(i = strlen(buf) - 1; i &amp;gt;= 0; i--)&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;19:  &lt;/span&gt;    sum += getPrice(buf[i]);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;20:  &lt;/span&gt;  printf(&lt;span style="color: #a31515;"&gt;"%d\n"&lt;/span&gt;, sum);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;21:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;return &lt;/span&gt;0;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;22:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;p&gt;上述程序中的 getPrice 函数用来计算每个字符的收费。注意上述程序中的 gets 函数是不安全的，如果输入超出 1000 个字符，将造成缓冲区溢出。同样由于这是 ACM 题，所以不用担心。&lt;/p&gt;&#xD;
&lt;p&gt;下面是 C++ 源程序：&lt;/p&gt;&#xD;
&lt;pre &gt;&lt;span style="color: black; font-weight: bold;"&gt;01:  &lt;/span&gt;&lt;span style="color: green;"&gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1567&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;02:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;03:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;iostream&amp;gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;04:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;#include &lt;/span&gt;&lt;span style="color: #a31515;"&gt;&amp;lt;string&amp;gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;05:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;06:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;using namespace &lt;/span&gt;std;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;07:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;08:  &lt;/span&gt;&lt;span style="color: blue;"&gt;int &lt;/span&gt;getPrice(&lt;span style="color: blue;"&gt;char &lt;/span&gt;c)&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;09:  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;10:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;'.' &lt;/span&gt;|| c == &lt;span style="color: #a31515;"&gt;' '&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;1;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;11:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;','&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;2;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;12:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;if &lt;/span&gt;(c == &lt;span style="color: #a31515;"&gt;'!'&lt;/span&gt;) &lt;span style="color: blue;"&gt;return &lt;/span&gt;3;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;13:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;return &lt;/span&gt;1 + (c - &lt;span style="color: #a31515;"&gt;'a'&lt;/span&gt;) % 3;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;14:  &lt;/span&gt;}&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;15:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;16:  &lt;/span&gt;&lt;span style="color: blue;"&gt;int &lt;/span&gt;main()&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;17:  &lt;/span&gt;{&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;18:  &lt;/span&gt;  string buf;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;19:  &lt;/span&gt;  getline(cin, buf);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;20:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;int &lt;/span&gt;sum = 0;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;21:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;for &lt;/span&gt;(string::iterator it = buf.begin(); it &amp;lt; buf.end(); it++)&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;22:  &lt;/span&gt;    sum += getPrice(*it);&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;23:  &lt;/span&gt;  cout &amp;lt;&amp;lt; sum &amp;lt;&amp;lt; endl;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;24:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;return &lt;/span&gt;0;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;25:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;p&gt;上述程序和 C 程序基本上是一样的，不过 getline 函数是安全的。&lt;/p&gt;&#xD;
&lt;p&gt;下面是 F# 源程序：&lt;/p&gt;&#xD;
&lt;pre &gt;&lt;span style="color: black; font-weight: bold;"&gt;01:  &lt;/span&gt;&lt;span style="color: green;"&gt;// http://acm.timus.ru/problem.aspx?space=1&amp;amp;num=1567&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;02:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;03:  &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;let &lt;/span&gt;getPrice c =&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;04:  &lt;/span&gt;  &lt;span style="color: blue;"&gt;match &lt;/span&gt;c &lt;span style="color: blue;"&gt;with&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;05:  &lt;/span&gt;  &lt;/span&gt;| &lt;span style="color: maroon;"&gt;'.' &lt;/span&gt;| &lt;span style="color: maroon;"&gt;' ' &lt;/span&gt;&lt;span style="color: blue;"&gt;-&amp;gt; &lt;/span&gt;1&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;06:  &lt;/span&gt;  | &lt;span style="color: maroon;"&gt;',' &lt;/span&gt;&lt;span style="color: blue;"&gt;-&amp;gt; &lt;/span&gt;2&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;07:  &lt;/span&gt;  | &lt;span style="color: maroon;"&gt;'!' &lt;/span&gt;&lt;span style="color: blue;"&gt;-&amp;gt; &lt;/span&gt;3&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;08:  &lt;/span&gt;  | x &lt;span style="color: blue;"&gt;-&amp;gt; &lt;/span&gt;1 + (int x - int &lt;span style="color: maroon;"&gt;'a'&lt;/span&gt;) % 3&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;09:  &lt;/span&gt;&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;10:  &lt;/span&gt;&lt;span style="color: blue;"&gt;let &lt;/span&gt;pricing str = str |&amp;gt; Seq.map getPrice |&amp;gt; Seq.sum&#xD;
&lt;span style="color: black; font-weight: bold;"&gt;11:  &lt;/span&gt;  &#xD;
&lt;span style="color: black; font-weight: bold;"&gt;12:  &lt;/span&gt;System.Console.ReadLine() |&amp;gt; pricing |&amp;gt; printfn &lt;span style="color: maroon;"&gt;"%d"&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;可以看出 F# 程序最简单明了，Seq.map 根据 getPrice 来计算每个字符的收费，再用 Seq.sum 来求和。&lt;/p&gt;&#xD;
&lt;hr /&gt;&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2008/12/08/1350510.html"&gt;返回目录&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/skyivben/aggbug/2229476.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/skyivben/archive/2011/10/30/2229476.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
