编写一个以文本为输入的程序,并生成一个再现该文本的程序
Write a program that takes text as input and produces a program that reproduces that text
最近我遇到了一个很好的问题,它变得既简单易懂,又难以找到任何解决方法。问题是:
编写一个程序,从输入中读取文本并打印其他文本程序输出。如果我们编译并运行打印的程序,它必须输出原始文本。
输入文本应该相当大(超过10000个字符)。
唯一(也是非常严格)的要求是,存档(即打印的程序)的大小必须严格小于原始文本的大小。这使得像这样显而易见的解决方案变得不可能
std::string s;
/* read the text into s */
std::cout << "#include<iostream> int main () { std::cout<<"" << s << ""; }";
我认为这里要使用一些归档技术。
不幸的是,这样的程序并不存在。
要知道为什么会这样,我们需要做一些数学运算。首先,让我们统计有多少长度为n的二进制字符串。每个比特可以是0或1,这为每个比特提供了两个选择之一。由于每个比特和n个比特有两个选择,因此总共有2个长度为n的二进制串。
现在,让我们假设我们想要构建一个压缩算法,它总是将长度为n的比特串压缩为长度小于n的比特字符串。为了使其工作,我们需要计算出有多少不同的长度小于n。好吧,这是由长度为0的比特串的数量,加上长度为1的比特串数量,加上将长度为2的比特串数目,等等给出的,一直到n-1。这个总数是
20+21+22+…+2n-1
通过一点数学运算,我们可以得到这个数字等于2n-1。换句话说,长度小于n的比特串的总数比长度为n的比特字符串的数量小一个。
但这是个问题。为了让我们有一个无损压缩算法,它总是将长度为n的字符串映射到长度最多为n-1的字符串,我们必须有某种方式将长度为n的每个比特串与某个较短的比特串相关联,这样就不会有两个长度为m的比特串与相同的较短比特流相关联。通过这种方式,我们可以通过将字符串映射到关联的较短字符串来压缩字符串,也可以通过反转映射来解压缩字符串。长度为n的两个比特串都不能映射到同一个较短的字符串,这一限制使得这种无损-如果两个长度为n的比特串映射到相同的较短的比特串,那么当需要解压缩字符串时,就无法知道我们压缩了两个原始比特串中的哪一个。
这就是我们遇到问题的地方。由于存在长度为n的2个不同的比特串,并且只有2个较短的比特串n-1个,因此我们不可能在不向同一较短串分配至少两个长度为n比特串的情况下将长度为n个的每个比特串与某个较短比特串配对。这意味着,无论我们多么努力,无论我们有多聪明,无论我们的压缩算法有多有创意,都有一个严格的数学限制,那就是我们不能总是让文本变短。
那么,这与你最初的问题是如何对应的呢?好吧,如果我们得到一个长度至少为10000的文本字符串,并且需要输出一个较短的程序来打印它,那么我们必须有某种方法将长度为10000的2个10000字符串中的每一个映射到长度小于10000的2<10000>-1个字符串上。该映射还有一些其他属性,即我们总是必须生成一个有效的程序,但这在这里无关紧要——根本没有足够的短字符串可供使用。因此,你想解决的问题是不可能的。
也就是说,我们可能能够得到一个程序,它可以将长度为10000的字符串中除一个外的所有字符串压缩为较短的字符串。事实上,我们可能会找到一种压缩算法来做到这一点,这意味着在概率为1-210000的情况下,任何长度为10000的字符串都可以被压缩。这是一个很高的概率,如果我们在宇宙的一生中一直在挑选字符串,我们几乎肯定永远不会猜到"一个坏字符串"。
为了进一步阅读,信息论中有一个概念叫做Kolmogorov复杂性,它是产生给定字符串所需的最小程序的长度。一些字符串很容易被压缩(例如,ababababababab),而另一些则不然(例如,sdkjhdbvljkhwqe2305089)。存在被称为不可压缩字符串的字符串,对于这些字符串,字符串不可能被压缩到任何更小的空间中。这意味着任何打印该字符串的程序都必须至少与给定字符串一样长。为了更好地介绍Kolmogorov复杂性,你可能想看看Michael Sipser的"计算理论导论,第二版"第6章,其中对一些较酷的结果进行了极好的概述。要想更严谨、更深入地研究,可以考虑阅读第14章"信息理论的要素"。
希望这能有所帮助!
如果我们谈论的是ASCII文本。。。
我认为这实际上可以完成,并且我认为文本将大于10000个字符的限制是有原因的(给你编码空间)。
这里的人说字符串不能压缩,但它可以。
为什么?
要求:输出原始文本
文本不是数据。当您读取输入文本时,您读取的是ASCII字符(字节)。其中包含可打印和不可打印的值。
举个例子:
ASCII values characters
0x00 .. 0x08 NUL, (other control codes)
0x09 .. 0x0D (white-space control codes: 't','f','v','n','r')
0x0E .. 0x1F (other control codes)
... rest of printable characters
由于必须将文本打印为输出,因此您对范围(0x00-0x08,0x0E-0x1F)不感兴趣。您可以通过使用不同的存储和检索机制(二进制模式)来压缩输入字节,因为您不必返回原始数据,而是返回原始文本。您可以重新计算存储值的含义,并将它们重新调整为要打印的字节。实际上,您将只释放非文本数据的数据,因此这些数据不可打印或输入。如果WinZip这样做,那将是一个巨大的失败,但对于您所声明的要求来说,这根本无关紧要。
由于要求文本为10000个字符,您可以保存255个字符中的26个,因此如果您的包装没有任何损失,您可以有效地节省大约10%的空间,这意味着如果您可以用1000个字符(10000个字符的10%)编码"解压缩",您就可以实现这一点。您必须将10个字节的组视为11个字符,然后根据229的范围,通过某种外推方法外推te 11。如果能够做到这一点,那么问题就可以解决。
尽管如此,它需要聪明的思维和编码技能,才能在1千字节内真正做到这一点。
当然,这只是一个概念性的答案,而不是一个功能性的答案。我不知道我是否能做到这一点。
但我有一种冲动,想为此付出2美分,因为每个人都觉得这是不可能的,因为我对此非常确信
问题中真正的问题是理解问题和需求。
您所描述的基本上是一个用于创建自解压zip档案的程序,只是一个小的区别,即常规的自解压zip存档将原始数据写入文件而不是stdout。如果你想自己制作这样一个程序,有很多压缩算法的实现,或者你可以自己实现例如DEFLATE(gzip使用的算法)。"外部"程序必须压缩输入数据并输出用于解压缩的代码,并将压缩的数据嵌入该代码中。
伪码:
string originalData;
cin >> originalData;
char * compressedData = compress(originalData);
cout << "#include<...> string decompress(char * compressedData) { ... }" << endl;
cout << "int main() { char compressedData[] = {";
(output the int values of the elements of the compressedData array)
cout << "}; cout << decompress(compressedData) << endl; return 0; }" << endl;
-
假设"字符"意味着"字节",并且假设输入文本可能包含至少与编程语言一样多的有效字符,则不可能对所有输入执行此操作,因为正如templatepedef所解释的,对于任何给定长度的输入文本,所有"严格较小"的程序本身都可能是长度较小的输入,这意味着可能的输入比可能的输出更多。(通过使用以"如果这是1,以下只是未编码的输入,因为它无法进一步压缩"位开头的编码方案,可以安排输出最多比输入长一位)
-
假设它足以对大多数输入(例如,主要由ASCII字符组成的输入,而不是所有可能的字节值)执行此操作,那么答案很容易存在:使用gzip。这就是它的长处。没有什么比这更好的了。您可以创建自解压档案,也可以将gzip格式视为"语言"输出。在某些情况下,使用完整的编程语言或可执行文件作为输出可能会更高效,但通常情况下,通过使用为该问题设计的格式(即gzip)来减少开销会更高效。
它被称为产生自提取归档的文件归档器。
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 在由Sublime文本3编译后在cmd上显示Java程序输出
- C++检查应用程序中的文本框值
- 在程序和基于文本的游戏和C++内重新启动程序
- 在程序/基于文本的游戏/C++内重新启动程序
- 我的C++程序只写入文本文件最后一个条目
- 如何在Windows窗体应用程序中打开txt文件并将行导入文本框
- C++程序的 Python 文本解析器?
- 在图像上覆盖文本的程序会产生无休止的字符串错误
- 创建程序以从给定的.txt文件中查找文本,替换并计算单词
- opengl 飞行模拟器应用程序中的文本呈现问题
- 在C Windows程序中显示文本文件内容
- C ++,否则文本程序不会进入我想要的途径
- 编写一个 C++ 程序以将文本文件转换为 HTML 文件
- C++可以从文本文件复制并粘贴到打开的Word程序中
- C :如何从格式的文本文件中读取许多数据到程序中
- C++ 从另一个程序窗口的内存中编辑文本
- 崇高文本 3 - 在终端中编译并运行 C++ 程序(路径包含空格)
- 如何在MFC多字节应用程序中显示西里尔文本?
- C++程序在 freopen 中读取大文本后停止工作