zoukankan      html  css  js  c++  java
  • 关于算法竞赛某些常见基础错误

    手(shou)误(jian)

    • 出错特征:程序执行流程出乎意料,结果不正确。

    • 出错样例:

      for (int i = 0; i < n; i++) {
          if (i = n)
              printf("%d
      ", i);
          else
              printf("%d ", i);
      }
      
    • 治疗方法:剁手。多剁两次就记住了。

    浮点数判等

    • 出错特征:WA到死。

    • 出错样例:

      double a = 1 / 3 * 3;
      double b = 1;
      if (a == b) {
          printf("Yes");
      }
      
    • 治疗方法:

      const double eps = 1e-5;
      double a = 1 / 3 * 3;
      double b = 1;
      if (abs(a - b) < eps) {
          printf("Yes");
      }
      
    • 注意点:eps到底取多少? 一般在1e-5到1e-8之间。有些题目卡eps。(就是莫名其妙的一个wa一个ac)

    声明变量和使用变量太远……

    • 出错特征:Output Limit Error 或 WA 或 RE 或 TE 或 机器爆炸。

    • 出错样例:

      题目:计算a+b。

      输入:t组数据,每组测试数据包含两个数a,b。

      输出:对于没组数据,输出a+b的值。每两组输出之间换行隔开

    • #include <cstdio>
      bool isFirst, t;
      int a, b;
      int main() {
          isFirst = true;
          scanf("%d", &t);
          while (t--) {
              scanf("%d%d", &a, &b);
              if (isFirst) {
                  isFirst = false;
              } else {
                  puts("");
              }
              printf("%d
      ", a + b);
          }
          return 0;
      }
      
      数据:
      3
      1 2
      2 3
      3 4
      
    • 治疗方法:先睡一觉。写出这种代码,你一定是太累了。

    忘记初始化

    • 出错特征:WA
    • 出错样例:比如每次使用vis之前没有清false之类。
    • 治疗方案:
      • 每个变量定义的同时就初始化。
      • 提交代码之前,检查所有定义的变量是否已经初始化。

    数组开小了

    • 出错特征:差别不大的会WA或TE。差别大的会RE。
    • 出错样例:眼花手抖导致的数组少个0。,“树”类问题数组只开了n(应该要4n)
    • 治疗方案:数组开的足够大。

    Ctrl+C && Ctrl+V

    • 出错说明:复制一段代码然后粘贴再修改的方式编程。常常出现没修改干净的问题。常出现在搜索题或输出图形的题。
    • 出错特征:WA
    • 出错样例:暂缺
    • 治疗方法:
      • 不要复制代码。把能重用的地方封装成函数然后再用(往往比较费时间)
      • 采用复制代码方式。修改后然后检查3遍,当WA的时候,重点检查此处。优先重写此处。(即将复制的代码列为高危代码)
    • PS:写工程的时候,不要复制代码……除非你的工程不需要维护(比如作业)

    建议的代码书写方式

    • 良好的代码风格。包括但不限于
      • 有意义的变量名(起名字真的是个技术,没那麼简单,就能找到,聊得来的伴
      • 缩进
      • 大括号的位置(选择一个风格保持统一)
      • 有必要的空格使代码清晰(比如:int a = (10*3/2 + 10)/3
      • C++式的变量声明方式(即等到要用的时候再声明,不要在函数开头声明一堆,然后再用)
    • 防御性编程
      • 声明变量后立即初始化,不管是否必要。
      • 指针不用后立即清空,不管是否必要。

    浮点数相关的陷阱

    误差修正

    简述

    因为被计算机表示浮点数的方式所限制,CPU在进行浮点数计算时会出现误差。如执行0.1 + 0.2 == 0.3结果往往为false,在四则运算中,加减法对精度的影响较小,而乘法对精度的影响更大,除法的对精度的影响最大。所以,在设计算法时,为了提高最终结果的精度,要尽量减少计算的数量,尤其是乘法和除法的数量。

    浮点数与浮点数之间不能直接比较,要引入一个eps常量。eps是epsilon(εε)的简写,在数学中往往代表任意小的量。在对浮点数进行大小比较时,如果他们的差的绝对值小于这个量,那么我们就认为他们是相等的,从而避免了浮点数精度误差对浮点数比较的影响。eps在大部分题目时取1e-8就够了,但要根据题目实际的内容进行调整。

    模板代码

    // sgn返回x经过eps处理的符号,负数返回-1,正数返回1,x的绝对值如果足够小,就返回0。
    const double eps = 1e-8;
    int sgn(double x) { return x < -eps ? -1 : x > eps ? 1 : 0; }
    
    整型比较 等价的浮点数比较
    a == b sgn(a - b) == 0
    a > b sgn(a - b) > 0
    a >= b sgn(a - b) >= 0
    a < b sgn(a - b) < 0
    a <= b sgn(a - b) <= 0
    a != b sgn(a - b) != 0

    输入输出

    scanf输入浮点数时,double的占位符是%lf,但是浮点数doubleprintf系列函数中的标准占位符是%f而不是%lf,使用时最好使用前者,因为虽然后者在大部分的计算机和编译器中能得到正确结果,但在有些情况下会出错(比如在POJ上)。

    开方

    当提供给C语言中的标准库函数double sqrt (double x)x为负值时,sqrt会返回nan,输出时会显示成nan-1.#IND00(根据系统的不同)。在进行计算几何编程时,经常有对接近零的数进行开方的情况,如果输入的数是一个极小的负数,那么sqrt会返回nan这个错误的结果,导致输出错误。解决的方法就是将sqrt包装一下,在每次开方前进行判断。

    示例代码

    double mysqrt(double x) { return max(0.0, sqrt(x)); }
    

    负零

    大部分的标程的输出是不会输出负零的,如下面这段程序:

    int main() {
        printf("%.2f
    ", -0.0000000001);
        return 0;
    }
    

    会输出-0.00。有时这样的结果是错误的,所以在没有Special Judge的题目要求四舍五入时,不要忘记对负零进行特殊判断。

    但有的标程也不会进行这样的特殊判断,所以在WA时不要放弃摸索。

    写在最后

    “年代久远”的缘故,上面的错误已经找不到原来的代码了。 如果各位刷题时出现闹鬼代码,欢迎编辑在此,以供后人抓鬼。

  • 相关阅读:
    NSString 处理
    我的第一个IOSDemo
    NSArray创建和使用
    NSDate
    NSDictionary
    flash全屏代码
    getBounds
    运用递归随机出与上一个数不重复的数
    标签跟随鼠标移动
    保存数据到本地
  • 原文地址:https://www.cnblogs.com/RioTian/p/14070438.html
Copyright © 2011-2022 走看看