【转】信息奥赛一本通1185:单词排序(OJ题目描述有问题)

博客围绕单词排序题目展开,题目要求按字典序输出单词且重复单词只输出一次。作者起初按接收一行单词编程提交答案错误,后经他人提示改为接收多行单词才通过。文中还给出了两种程序代码,提醒后续做题者注意题目描述陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:https://blog.youkuaiyun.com/mengdicfm/article/details/88384963

1185:单词排序

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 3474 通过数: 1685
【题目描述】
输入一行单词序列,相邻单词之间由1个或多个空格间隔,请按照字典序输出这些单词,要求重复的单词只输出一次。(区分大小写)

【输入】
一行单词序列,最少1个单词,最多100个单词,每个单词长度不超过50,单词之间用至少1个空格间隔。数据不含除字母、空格外的其他字符。

【输出】
按字典序输出这些单词,重复的单词只输出一次。

【输入样例】
She wants to go to Peking University to study Chinese
【输出样例】
Chinese
Peking
She
University
go
study
to
wants

这题表述有问题,题目说是一行单词序列,但是我编程序接收一行单词序列时,样例都能过,自己输入英文句子,也能过。提交时所有点都是“答案错误”(看我的程序一代码)。后来,问了别人,别人告诉我,是要接收多行单词,把程序改了一下,反复接收一行单词,并记录,就过了。(看我的程序二代码)
区别就是把getline(cin,danci)放在while循环中,反复接收单词序列,直到文件结束,停止接收(因为测试OJ是通过文件进行输入输出的)。

希望后面的人不要跟我一样被题目描述坑了哦。

程序一(所有点提示答案错误):

//1185:单词排序
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[101][51];
int len,i,k=0,j;
string danci;

void paixu(char a[101][51],int start,int end) //自定义排序函数,对字二维符串数组排序
{
    char tmp[51];
    int i,j;
    for(i=end-1;i>=1;i--)
    {
        for(j=start;j<=i;j++)
        {
            if(strcmp(a[j],a[j+1])>0) //如果字典序逆序,则交换 
            {
                strcpy(tmp,a[j]); //将a[j]字符串复制到临时字符串tmp中 
                strcpy(a[j],a[j+1]);
                strcpy(a[j+1],tmp);
            }
        }
        
    }
    return;
 } 
int main()
{
    bool flag=false;//是否遇到一个新单词,false表示没有遇到,true表示遇到了 
    memset(a,0,sizeof(a));
    getline(cin,danci);//接收单词序列,碰到换行结束,可以接收空格 
    danci=" "+danci+" ";//在单词序列前后加空格
    len=danci.length();

    j=0;
    for(i=0;i<len;i++)
    {
        
        if(danci[i]==' ') //碰到空格,表明不是一个单词 
        {
            flag=false;
            //a[k][j]='\0';
            
        }
        else //碰到的不是空格时 
        {
            if(flag==false)
            {
                k++;//新单词 
                j=0;
                flag=true;
                a[k][j]=danci[i];
                j++;
            }
            else //单词中间字母 
            {
                a[k][j]=danci[i];
                j++;
            }    
        } 
        
    }
    paixu(a,1,k);//对记录1至k的单词按字典序升序排序 
    for(i=1;i<=k;i++)
    {
        if(strcmp(a[i],a[i-1])==0)//如果和前面字符串相等,则不输出,相同字符串输出一次
        continue; 
        cout<<a[i]<<endl;
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
程序二(所有点通过):

//1185:单词排序
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char a[101][51];
int len,i,k=0,j;
string danci;

void paixu(char a[101][51],int start,int end) //自定义排序函数,对字二维符串数组排序
{
    char tmp[51];
    int i,j;
    for(i=end-1;i>=1;i--)
    {
        for(j=start;j<=i;j++)
        {
            if(strcmp(a[j],a[j+1])>0) //如果字典序逆序,则交换 
            {
                strcpy(tmp,a[j]); //将a[j]字符串复制到临时字符串tmp中 
                strcpy(a[j],a[j+1]);
                strcpy(a[j+1],tmp);
            }
        }
        
    }
    return;
 } 
int main()
{
    bool flag=false;//是否遇到一个新单词,false表示没有遇到,true表示遇到了 
    memset(a,0,sizeof(a));
    while(getline(cin,danci))//反复接收单词序列(接收多行单词序列),碰到换行结束,可以接收空格 
    {
    danci=" "+danci+" ";//在单词序列前后加空格
    len=danci.length();
    j=0;
    for(i=0;i<len;i++)
    {
        
        if(danci[i]==' ') //碰到空格,表明不是一个单词 
        {
            flag=false;
            //a[k][j]='\0';
            
        }
        else //碰到的不是空格时 
        {
            if(flag==false)
            {
                k++;//新单词 
                j=0;
                flag=true;
                a[k][j]=danci[i];
                j++;
            }
            else //单词中间字母 
            {
                a[k][j]=danci[i];
                j++;
            }    
        } 
        
    }    
    }
    
    
    paixu(a,1,k);//对记录1至k的单词按字典序升序排序 
    for(i=1;i<=k;i++)
    {
        if(strcmp(a[i],a[i-1])==0)//如果和前面字符串相等,则不输出,相同字符串输出一次
        continue; 
        cout<<a[i]<<endl;
    }
    return 0;
}
--------------------- 
作者:mengdicfm 
来源:优快云 
原文:https://blog.youkuaiyun.com/mengdicfm/article/details/88384963 
版权声明:本文为博主原创文章,转载请附上博文链接!

<think>好的,我现在需要回答用户关于CRC32是否可逆的问题。首先,我需要理解用户的需求。他们想知道CRC32算法是否可逆,也就是说,能否从CRC32的校验值反推出原始数据。此外,用户还希望了解其原理和分析过程。 首先,我应该回顾CRC32的基本原理。CRC是循环冗余校验的缩写,主要用于检测数据传输或存储中的错误。CRC32生成的是一个32位的校验值。根据引用[3],CRC基于多项式除法,将数据视为二进制系数多项式,然后除以生成多项式,得到余数作为校验值。这个过程是确定性的,相同的输入总是得到相同的CRC32值。 接下来,关于可逆性。从数学上来说,CRC32是一个哈希函数,将任意长度的数据映射到固定长度的32位值。由于它是散列函数,理论上会有多个不同的输入产生相同的CRC32值,这就是哈希碰撞。引用[1]提到,CRC多项式是线性的,容易过改变数据达到碰撞,但位数增加会降低碰撞几率。由于CRC32的输出空间远小于输入空间,所以它不是一一对应的,因此不可逆。 但用户可能想知道是否存在某种方法过CRC32值恢复原始数据。这里需要考虑CRC32的结构。CRC计算是线性的,这意味着可能存在一些数学上的逆运算,但由于输入数据长度不确定,且存在无数可能的输入对应同一个CRC值,所以无法唯一确定原始数据。例如,即使知道CRC32值和生成多项式,也只能确定原始数据属于某个等价类,无法确定具体是哪一个。 此外,引用[4]提到MD5和SHA1是更复杂的哈希算法,而CRC32相对简单。虽然MD5等也不可逆,但CRC32的线性结构可能让某些部分逆运算成为可能,比如已知部分数据的情况下,可以计算另一部分。例如,如果数据长度固定,可能过解线性方程组来找到可能的原始数据。但一般情况下,数据长度不固定,这种方法不可行。 总结来说,CRC32在一般情况下不可逆,因为信息丢失且存在碰撞。但在特定约束条件下,如固定数据长度,可能存在部分逆运算的可能。需要分情况讨论,并解释其数学原理和实际应用中的限制。 现在需要组织这些思路,确保符合用户的要求:结构清晰,使用正确的LaTeX格式,生成相关问题,并引用提供的资料。需要检查是否遗漏了关键点,例如CRC的线性结构如何影响可逆性,以及实际中的碰撞概率等。</think>### CRC32的可逆性分析 #### 1. **CRC32的不可逆性** CRC32是一种**不可逆的哈希函数**,其设计目标是过32位校验值检测数据错误,而非加密或数据恢复。以下从数学原理和实际应用两方面说明: - **数学原理** CRC32将数据视为二进制多项式$D(x)$,与生成多项式$G(x)$进行模2除法运算,得到余数作为校验值$R(x)$,即: $$D(x) = Q(x) \cdot G(x) + R(x)$$ 其中$R(x)$的位数固定为32位。由于输入数据长度可变(可能远超32位),而输出固定为32位,**信息在计算过程中被丢弃**,无法过$R(x)$唯一还原原始数据[^3]。 - **碰撞与线性结构** CRC32的线性特性(如引用[1]所述)使其容易过调整数据达到碰撞。例如,若已知数据块$D_1$的CRC32值为$C$,则可以过构造$D_2 = D_1 \oplus \Delta$($\Delta$为特定掩码),使得$D_2$的CRC32值也为$C$。这表明**多个不同输入可生成相同校验值**,进一步说明其不可逆性。 #### 2. **特定条件下的部分可逆性** 在**已知部分数据信息**或**固定数据长度**的场景中,可能存在有限的可逆操作: - **固定长度数据**:若数据长度$n$已知且较小(如$n \leq 32$位),可过求解线性方程组还原数据。但对于任意长度数据,此方法不可行。 - **已知部分数据**:若已知部分数据内容,可过调整未知部分使整体CRC32匹配目标值。例如,在协议逆向工程中,过修改尾部字节修正校验值。 #### 3. **与MD5/SHA1的对比** - CRC32的线性结构使其计算速度快,但安全性低(如引用[4]对比MD5)。MD5/SHA1等加密哈希函数过非线性操作增强抗碰撞性,但仍不可逆。 - CRC32的碰撞概率为$1/2^{32}$(约$4.3 \times 10^{-9}$),实际应用中需权衡效率与可靠性(如引用[1]提到CRC64更可靠)。 #### 4. **实际应用中的限制** - **错误检测**:CRC32用于网络传输、存储校验等场景,依赖其错误检测能力,而非数据恢复。 - **数据完整性争议**:由于碰撞概率存在,CRC32不适合用于安全敏感场景(如密码存储),需结合其他哈希算法[^1][^4]。 ```python # CRC32计算示例(Python) import binascii data = b"hello world" crc32 = binascii.crc32(data) & 0xFFFFFFFF print(f"CRC32值: {crc32:08x}") # 输出: CRC32值: 0x0d4a1185 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值