a11889吧 关注:6贴子:49

[转][KSの个人向教程]C语言、C++与算法竞赛学习笔记

只看楼主收藏回复

采用刘汝佳《算法竞赛入门经典(第2版)》、《C++ Primer》与《算法导论》共同学习。
本帖仅用于分享个人学习C语言、C++与算法竞赛的心得,如有错误请指出。
本帖不会含有图片、视频资料,请各位善于动手实践。
由于使用GCC编译器,本帖中代码可能偏向于C++标准,请注意区分。
本帖之代码片段均使用Dev-C++/MinGW64编译,可能与部分OJ的要求不相同。
开坑于2014/12/1
转载请注明原帖地址、原作者名称及相关注意事项,谢谢。
KSkun


IP属地:上海1楼2014-12-14 13:42回复
    Day 1 《算法竞赛》第1部分 第1章
    本笔记对新手可能不太友好,建议有基础再来阅读。
    1.1 算术表达式
    C语言(或是通用于其他语言)的算术运算符有:
    + - * / %
    + 算术加
    - 算术减
    * 算术乘
    / 算术除
    % mod
    也可以包含math.h头文件使用更多的算术运算函数,例:
    #include <stdio.h>
    #include <math.h>
    int main() {
    int a = sqrt(4); //sqrt(float f)用于开方
    printf("%d\n", a);
    return 0;
    }
    //Input: null; Output: 2
    复制代码12/9补充:需要注意的是,这里的sqrt()函数传入和返回的都是double值,强制转型为int值会有误差,请谨慎使用
    算术运算式的结果如下:
    int / int = int
    float / float = float
    int - float = float
    以此类推
    那么上面说到的scanf()和printf()函数怎么用呢
    scanf("%d", &a);
    //%d表示输入一个int, 如果替换成%f就表示输入一个float, 此处可以加上格式比如"%d %d\n%d"
    printf("%d %d\n%.1f", a, b, c);
    // \n为换行符, %.1f表示输出的浮点数保留1位小数


    IP属地:上海2楼2014-12-14 13:43
    回复
      Day 2.1 《C++ Primer》第一章
      1.2 初始输入和输出
      C++中输入输出是对象形式的。
      std::cin >> a;
      std::cout << a;
      复制代码这里需要include一个C++头文件才能获得这个namespace里的对象
      #include <iostream>
      复制代码那么由C的function变为C++的object自然会简单很多
      std::cin >> 对象;
      std::cout << 对象;
      //同时std::endl表示换行符
      复制代码如果不想用std::的话可以加上如下语句
      using namespace std;
      复制代码这样编译器就会认为你默认在std namespace里调用了。
      cin、cout对象是输入/出数据流,>>是输入运算符,而<<是输出运算符,I/O的过程就是向流写入、取出数据。


      IP属地:上海3楼2014-12-14 13:43
      回复
        1.3 注释简介
        这个不需要多讲,大家都熟悉。
        //单行注释
        /* 多行注释
        * 像这样
        * 可以持续很多行
        */
        // /*
        // * 单行注释中的多行注释是被忽略的
        // */
        /* 也可以这么用 */
        复制代码晚上回来写算法竞赛~


        IP属地:上海4楼2014-12-14 13:44
        回复
          Day 2.2 《C++ Primer》第1章
          1.4 控制流
          首先是俩循环语句,不多说,看示例。
          while(condition)
          statement
          //while循环当条件为true时继续循环,为false时停止循环,先检查条件再执行循环
          for(init-statement; condition; expression)
          statement
          //for循环括号里一个初始化语句一个条件一个表达式不需要多讲,先后顺序同while
          复制代码这里顺便讲一下赋值运算符和前后缀递增/减运算符
          运算符类型 运算符 作用
          赋值运算符 = 将右边的值赋给左边的变量
          复合赋值运算符 += 将右边的值加给左边的变量
          复合赋值运算符 -= 将右边的值减给左边的变量
          复合赋值运算符 *= 将右边的值乘给左边的变量
          复合赋值运算符 /= 将右边的值除给左边的变量
          递增运算符 ++ 将变量值加1
          递减运算符 -- 将变量值减1


          IP属地:上海5楼2014-12-14 13:44
          回复
            赋值运算符大家都知道是什么意思,所以这里解释一下“左值”、“右值”和递增/减运算符的用法0。来看两个问题
            (1)++a和a++有什么区别呢?
            (2)来看一段代码:
            #include <stdio.h>
            int main() {
            int a = 0;
            ++++a;
            printf("%d\n", a);
            return 0;
            }//Input: null; Output: 2
            复制代码那么这里的++++a是应该理解为什么呢?


            IP属地:上海6楼2014-12-14 13:44
            回复
              左值、右值的概念解读:
              根据它们的名称,我们可以简单地理解为左值是能位于赋值运算符左侧的对象,而右值则是右侧,但需要知道的是这是不准确的。
              C++ Primer是这么解释的:当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。
              这么解释是没有错的,简单地再次归纳一下,赋值运算就是将右侧对象的值写入左侧对象中,即左值是可“写”的,右值是可“读”的。
              让我们用一个例子进一步地解释。++a与a++的关系,那么让我们进行一些实验:

              #include <stdio.h>
              int main() {
              int a = 0;
              ++a = 8;
              printf("%d\n", a);
              }//Input: null; Output: 8
              复制代码②
              #include <stdio.h>
              int main() {
              int a = 0;
              a++ = 8;
              printf("%d\n", a);
              }//Errored
              复制代码


              IP属地:上海7楼2014-12-14 13:44
              回复
                运行①的时候,我们发现编译器没有报错,说明++a是一个左值,这句根据运算符优先表可以转化为(++a) = 8;意思是说先对a进行递增运算,然后赋值8给a,此时++a返回的是一个对象a,确实是一个左值。
                而在编译②的时候,编译器给出了这样的错误:[Error] lvalue required as left operand of assignment,意为赋值运算左边的操作数必须为左值,即a++不是一个左值。此句应理解为(a++) = 8;,但由于a++返回的是一个右值(后面可能会讲到,C++11之前返回的是一个常量,常量的值为递增运算前a的值),该赋值语句并不合法,因此编译器报出了编译错误。由此,我们了解了左值和右值的实质。
                接下来是对问题(2)的解读,由上面所述,我们可以得知这句语句应该理解为++(++a),不必多讲。
                1.4.3在Day 3或Day 4讲解。


                IP属地:上海8楼2014-12-14 13:44
                回复
                  Day 3.1 《算法竞赛》第1章
                  1.2 变量及其输入
                  Problem 1 a+b问题
                  Problem 2 圆柱体的表面积
                  P1不用多讲
                  #include <stdio.h>
                  int main() {
                  int a, b;
                  scanf("%d%d", &a, &b);
                  printf("%d %d\n", a + b);
                  return 0;
                  }
                  复制代码


                  IP属地:上海9楼2014-12-14 13:45
                  回复
                    P2需要注意的是圆柱体面积计算需要用到π这个常量,应该使用双精度浮点数作为变量以获得更精确的结果。
                    #include <stdio.h>
                    #include <math.h>
                    int main() {
                    const double pi = acos(-1.0);//求出π的值并保存为常量
                    double r, h, s1, s2, s;
                    scanf("%lf%lf", &r, &h);
                    s1 = pi * r ^ 2;
                    s2 = 2 * pi * r * h;
                    s = s1 * 2.0 + s2;
                    printf("Area = %.3f\n", s);
                    return 0;
                    }
                    复制代码


                    IP属地:上海10楼2014-12-14 13:45
                    回复
                      Day 3.2 《C++ Primer》 第1章
                      1.4.3 读取数量不定的输入数据
                      这里实际上是对cin和while循环的利用,不多赘述,看示例。
                      #include <iostream>
                      using namespace std;
                      int main() {
                      int a = 0, sum = 0;
                      while(cin >> a) sum += a;
                      cout << sum << endl;
                      return 0;
                      }
                      复制代码


                      IP属地:上海11楼2014-12-14 13:45
                      回复
                        这是一个不给定数据数量的计算总和的程序,由于不管是C语言的scanf还是C++的cin读取数据的时候都会返回一个状态,我们便可以利用这个状态。这里意为一旦读取失败就终止循环。
                        需要注意的是,当我们输入数据的时候,输入完成所有数据,但程序还没停止请求输入,这时我们要在数据的末尾加一个文件结束符。
                        在Windows中,文件结束符可以用Ctrl+F输入,在你的调试窗口内可能会显示为“^F”。


                        IP属地:上海12楼2014-12-14 13:45
                        回复
                          1.4.3节之后,C++ Primer又讲了几个编译错误,这里稍微提一下。
                          语法错误(Syntax Error):程序员犯了C++语言文法上的错误。
                          例如
                          int main {}
                          复制代码就是有语法错误的语句段,这里的main函数没有参数列表,是非法的。


                          IP属地:上海13楼2014-12-14 13:45
                          回复
                            类型错误(Type Error):向不对应的类型使用不对应的操作。
                            例如
                            int a = "wow";
                            复制代码就是有类型错误的语句段,这里的a变量是int类型的,但我们却尝试将字符串"wow"的值赋给它。


                            IP属地:上海14楼2014-12-14 13:45
                            回复
                              声明错误(Declaration Error):使用未声明的对象或者错误地声明。
                              例如
                              #include <iostream>
                              int main() {
                              cout << "Declaration Error!" << endl;
                              return 0;
                              }
                              复制代码就是有声明错误的程序,这里的cout在std这个namespace里声明,而我们并没有用std::调用它或者using namespace std;。


                              IP属地:上海15楼2014-12-14 13:46
                              回复