洛谷 P8598 错误票据

题目背景

某涉密单位下发了某种票据,并要在年终全部收回。

题目描述

每张票据有唯一的 ID 号,全年所有票据的 ID 号是连续的,但 ID 的开始数码是随机选定的。因为工作人员疏忽,在录入 ID 号的时候发生了一处错误,造成了某个 ID 断号,另外一个 ID 重号。

你的任务是通过编程,找出断号的 ID 和重号的 ID。

数据保证断号不可能发生在最大和最小号。

输入格式

一个整数N(N<100) 表示后面数据行数,接着读入 N 行数据,每行数据长度不等,是用空格分开的若干个(不大于 100100 个)正整数(不大于 105105),每个整数代表一个 ID 号。

输出格式

要求程序首先输入要求程序输出 11 行,含两个整数 m,n,用空格分隔,其中,m 表示断号 ID,n 表示重号 ID。

输入输出样例

输入输出
2
5 6 8 11 9 #1
10 12 9 #2
7 9
6
164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196 #1
172 189 127 107 112 192 103 131 133 169 158 #2
128 102 110 148 139 157 140 195 197 #3
185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190 #4
149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188 #5
113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119 #6
105 120

PS:#后面的数字是行数的意思

代码

#include<stdio.h>
#include<iostream>
#define MAX 100
using namespace std;
int main(){
    int length;
    int p,q;
    int n,m=0;
    cin>>n;
    int array[MAX];

     for(int i=0;i<MAX;i++){
        cin>>array[i];
        char c;
        cin.get(c);
        if(c=='\n'){
            m++;
        }
        if(m>n-1){
            length=i+1;
            break;
        }
    }
     
    for(int i=0;i<length-1;i++){
        for(int j=0;j<length-1-i;j++){
            if(array[j]>array[j+1]){
                int temp=array[j];
                array[j]=array[j+1];
                array[j+1]=temp;
            }
        }
    }
    int j=0;
    int k=j+array[0];
    for(j=0;j<length;j++){
        
        if(array[j]!=k){
            p=array[j]-1;
            k++;
        }
        k++;
        if(array[j]==array[j+1]){
            q=array[j];
            k--;
        }
    }
    cout<<p<<' '<<q;
    return 0;
}

思路

        看到这道题目,我首先想到将输入的数据存放到一个int型的数组中,然后再遍历找出有问题的数据。

代码解析(3步)

1、输入数据并合理退出循环

2、为数组排序,方便查找

3、遍历数组找出不合格的数据

参数含义
length在输入的数据存到数组后,记录数组的长度
p记录断号ID的位置
q记录重复ID的位置
nn行数据
m记录人为输入回车的数量
array[MAX]存放数据的数组

1、输入数据并合理退出循环

for(int i=0;i<MAX;i++){
        cin>>array[i];
        char c;
        cin.get(c);
        if(c=='\n'){
            m++;
        }
        if(m>n-1){
            length=i+1;
            break;
        }
    }

        先循环输入数据,但是这里我碰到了一个问题,就是数组的大小是固定的,为MAX,但是我们输入数据时的数量是可变的,还有题目的要求,输入N行数据。那么,我们如何成功输入数据并让循环顺利退出呢?

        上述代码定义了一个char类型的临时变量c,用cin.get()函数来接收之前输入数据时残留在缓存中的换行符(当用cin>>读取数据时候,最后的换行符会残留在cin缓存中)。然后再令m++,记录换行符的数量,当m超过我们想要输入的n行数据后,就利用break语句退出循环,并且让length记录i的值,方便后面循环使用。

问题

1、为什么是m>n-1而不是m>n?

        假设输入两行数据时,此时n=2,数据如下。

2
5 6 8 11 9
10 12 9

       总共按下三个换行符,但是第一个换行符是在循环外完成的,不做考虑。

        按下另外两个换行符要执行if语句,m=2,2要大于一个数,所以右边必须是1,n-1就是1了。

        PS:一定要设置m的初始值为0,要不然编译器

2、为什么是length=i+1而不是length=i?

        当缓存池中最后一个数据被编译器读取时,i还没有进行自加,当循环结束时,i才会自加,编译器读取数据时会比i++慢一步。如图。

        

        输入的数据还是题目中m=2时的数据。可以看到,当if语句准备要break(此时m=2,n=2,下一步编译器就会执行n-1,跳出循环),array数组中已经存了8个数据了,但是此时i的值还是7,那么i值什么时候自增呢?

        答案当然是不会了,因为有break语句,程序会跳出循环。没有break语句时,代码中黄色的条条就会跳到循环的开头,就是for(int i=0;i<MAX;i++)这一句,因为i++不就在这里嘛。

        综上所述,length时要等于i+1才合理的。

2、为数组排序,方便查找

for(int i=0;i<length-1;i++){
        for(int j=0;j<length-1-i;j++){
            if(array[j]>array[j+1]){
                int temp=array[j];
                array[j]=array[j+1];
                array[j+1]=temp;
            }
        }
    }

        一个简单的冒泡排序。

        PS:此时数组长度知道了,用不到MAX了,用length就好。

3、遍历数组找出不合格的数据

    int j=0;
    int k=j+array[0];
    for(j=0;j<length;j++){
        
        if(array[j]!=k){
            p=array[j]-1;
            k++;
        }
        k++;
        if(array[j]==array[j+1]){
            q=array[j];
            k--;
        }
    }

        请先忽略j和k这两个变量。

        for循环遍历数组,两个if语句找出不合格的数据。

        第一个if语句

                题目要求是找出中断的一个数字,如图。

012345
345789

        上面一行是j的值(也是数组下标),下面一行是数据。

        因为下面一行数据也是递增的,虽然有断层。让下标加上数据的第一个数,这个值就是数据了(断层前的数据),判断断层的条件就出来了,就是当j+array[0]不等于array[i]时,就记录下这个断层,同时要在if语句中让j+array[0]自加,因为array[i]已经断层了一次了,已经跳过一个数了,在表中就是直接从5到7了,为了不影响后面的数据,我们就修好断层,让if语句另外一边(j+array[0])也自加一次。

        记得要让j+array[0]数据不能收到循环的影响,所以要定义在循环的外面(因为j在循环里会自加),用一个变量k就行,让k代替j+array[0]在循环里工作。同时让k和j保持同步的状态,在if语句外自增就行,就是k++。

        用变量p来记录断层,在表格中3和对应的7属于断层,所以让p=6就行,代码就是p=array[j]-1;

        第二个if语句

        当数组中相邻数据相等时就用q记录,记得要让k--。如图

012345
344567

        数字4重复了,此时第一个if语句中,array[i]就会比另外一边慢了一步,所以要让k这个变量等一下它,所以要k自减一下;

小结

                此文章是我发布的第二篇文章,还有很多不成熟的地方,代码有错也欢迎大家提出来或者私信我。代码也不一定是最优质的,主要是想记录下自己的思路和大家分享一下。喜欢我的文章就点个小小的爱心吧!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值