标签:1991 编码 01 213 int ACM len 长度 string
问题描述:
考虑下面的01串序列:
0,00,01,10,000,001,010,011,100,101,110,0000,0001,···,1101,1110,00000,···
首先是长度为1的串,然后是长度为2的串,依此类推。如果看成二进制,相同长度的后一个串等于前一个串加1。注意上述序列中不存在全为1的串。你的任务是是编写一个解码程序。
输入格式:可能有多组数据,对于每组数据,首先输入一个编码头,则上述序列的每个串依次对应编码头的每一个字符。接下来是编码文本(可能有多行组成,你应当把它们拼成一个长长的01串)。编码文本由多个小节组成,每个小节的前三个数字代表小节中每个编码的长度(用二进制表示),然后是各个字符的编码,以全1结束(例如,编码长度为2的小节以11结束)。编码文本以编码长度为000的小节结束。
输出格式:对于每组数据,输出其编码文本解码后的结果。
输入数据:
TNM AEIOU
0010101100011
1010001001110110011
11000
$#**\
0100000101101100011100101000
输出数据:
TAN ME
##*\$
思路:原理比较简单,主要是怎么找到编码头和01串之间的对应关系,假设编码头中的字符从0开始编码。
观察01串的规律,长度1的有1个,长度2的有3个,长度3的有7个。。。长度n的有2^n-1个。。。
那么长度为n的第一个01串,其之前有多少个元素呢,显然有1+3+7+...+(2^(n-1)-1)个,根据等比数列求和公式,其等于2^n-n-1
故,长度为n的第一个01串,其是第2^n-n个元素,下标从0开始,其对应编码头中字符的下标为2^n-n-1
相同长度的01串,其转化为十进制数字即为0,1,2,3...,所以一个01串t,其对应编码头字符的下标应该是2^len-len-1+num(t),其中len为t的字符串长度,num(t)为t所对应的10进制数字
个人代码:
#include <bits/stdc++.h>
using namespace std;
//二进制字符串转10进制数字
int str2ToNum10(string key)
{
int result = 0;
int len = (int)key.size();
for (int i = len - 1; i >= 0; --i)
{
if (key[i] == '1')
result += round(pow(2, len - 1 - i));
}
return result;
}
//解码
string fun(string head, string text)
{
//小节结束标志
bool eend = true;
string result = "";
//当前需要解码位置
int index = 0;
string t;//暂时存储截取的字符串
int codeLen;//编码长度
while (1)
{
if (eend)
{
t = text.substr(index, 3);
index += 3;
if (t == "000")
break;
codeLen = str2ToNum10(t);
eend = false;
}
else
{
t = text.substr(index, codeLen);
index += codeLen;
//全1,小节结束
int i;
for (i = 0; i < (int)t.size(); ++i)
if (t[i] == '0')
break;
if (i == (int)t.size())
eend = true;
else
{
int chIndex = round(pow(2, codeLen)) - codeLen - 1 + str2ToNum10(t);
result += head[chIndex];
}
}
}
return result;
}
int main()
{
vector<string>head, text;
string t, textPart = "";
while (getline(cin, t))
{
if (t[0] == '0' || t[0] == '1')
textPart += t;
else
{
head.push_back(t);
if (textPart != "")
text.push_back(textPart);
textPart = "";
}
}
text.push_back(textPart);
for (int i = 0; i < (int)head.size(); ++i)
cout << fun(head[i], text[i]) << endl;
return 0;
}
参考代码:
#include<stdio.h>
#include<string.h>
int readchar() {
for(;;) {
int ch = getchar();
if(ch != '\n' && ch != '\r') return ch;
}
}
int readint(int c) {
int v = 0;
while(c--) v = v * 2 + readchar() - '0';
return v;
}
int code[8][1<<8];
int readcodes() {
memset(code, 0, sizeof(code));
code[1][0] = readchar();
for(int len = 2; len <= 7; len++) {
for(int i = 0; i < (1<<len)-1; i++) {
int ch = getchar();
if(ch == EOF) return 0;
if(ch == '\n' || ch == '\r') return 1;
code[len][i] = ch;
}
}
return 1;
}
// 用于调试
void printcodes() {
for(int len = 1; len <= 3; len++)
for(int i = 0; i < (1<<len)-1; i++) {
if(code[len][i] == 0) return;
printf("code[%d][%d] = %c\n", len, i, code[len][i]);
}
}
int main() {
while(readcodes()) {
//printcodes();
for(;;) {
int len = readint(3);
if(len == 0) break;
//printf("len=%d\n", len);
for(;;) {
int v = readint(len);
//printf("v=%d\n", v);
if(v == (1 << len)-1) break;
putchar(code[len][v]);
}
}
putchar('\n');
}
return 0;
}
总结:
1)参考代码中,将每个len和value对用的编码头字符存储在二维数组中,其和个人代码的根据01串求对应字符下标实际上是一致的。
code[8][1<<8];
2) 在本题中可以学到,要善于利用位运算符<<,1<<5是二进制100000,即2^5;1<<5-1是二进制11111(5个1);同理1<<n是2^n,1<<n-1是二进制的n个1
标签:1991,编码,01,213,int,ACM,len,长度,string 来源: https://blog.csdn.net/qq_42283621/article/details/110822364
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。