细节知识+奇淫巧技

  • puts()函数 
    puts()函数用来向标准输出设备(屏幕)写字符串并换行, 其调用格式为:
    puts(s); 其中s为字符串变量(字符串数组名或字符串指针)。
    puts()函数的作用与语printf("%s ", s)相同。

    gets()函数
    gets()函数用来从标准输入设备(键盘)读取字符串直到回车结束, 但回车符不属于这个字符串。其调用格式为:
    gets(s);
    其中s为字符串变量(字符串数组名或字符串指针)。
    gets(s)函数与scanf("%s", &s)相似, 但不完全相同, 使用scanf("%s", &s)函数输入字符串时存在一个问题, 就是如果输入了空格会认为输入字符串结束,空格后的字符将作为下一个输入项处理, 但gets() 函数将接收输入的整个字符串直到回车为止。
  • 结构体排序, 定义结构体 struct lzl { string s; int a,b; }x[100]; 然后 定义函数,bool cmp() { } 用sort函数来排序 就是这样:sort(x,x+n,cmp); 
  • 不包含空白字符,可以安全用scanf输入;
  • 做浮点数计算相关的题目要注意两点:

    1) 用double ,不要用 float,float精度不够;

    2) double 是用 %lf 读入的,不是 %f。输出可以用 %f;

    3) 为避免出现 -0.000这样的输出,对要输出的值要先判断是不是足够接近0,如果是,就直接输出 0.0。 例如如果要保留小数点后面 n位,那么 eps 就取 10的-(n+1)次方,然后 认为 数的绝对值小于 eps时,就是0;

    4)不要用 a == b的办法判断两个浮点数是否相等,包括不要用  a== 0的办法判断浮点数 a是否等于0,因为浮点数是有误差的。 应该用  a-b > -eps && a-b < eps  ,即a和b的差的绝对值小于某个很小值 eps的办法来判断a和b是否相等。如果结果要保留小数点后面n位,那么 eps可以取 10的-(n+1)次方。

  • 变量应当初始化,比如在有的题目里面:

    ....

    int main()

    {    int sum;

        ....

        ...

        return 0;

    }

    这个sum是用来在后面求和用的,那就应该有个初始值,比如:

    int sum = 0;

    否则,它的初始值就是随机的,那么后面的求和结果自然不对

    但是经常有同学说:在本机运行是对的,交上去就不对了。那是你人品好,那些没初始化的局部变量,在你本机运行时,碰巧它初始值就是0,所以你的程序就对了。交上去就没这么走运。

    变量一定要初始化!

    变量一定要初始化!

    变量一定要初始化!

    重要的事情说三遍。

  • 奇数 * 奇数 = 奇数
    奇数 * 偶数 = 偶数
    奇数 + 偶数 = 奇数
    奇数 + 奇数 = 偶数

                 s[i]-'a' + 'A'  (-32    //小写字母变大写
 ch = ch + 'a'- 'A';     //大写字母变小写

C语言s[i]-'a'是什么意思_百度知道

ans:,s[i]里面应该存储的是字符吧,如果大写字母,s[i]-'a',应该是转换成小写,如果是其他的字符应该是将去'a'的ASCII码.

  • 通常使用二维字符数组是为了在程序中存储一些字符串关键字。用这样的方式来初始化就最简单不过了。
  •     //字符数组;数组内容存放的元素是字符(char)

        //字符串数组:数组内存放的元素是字符串

        //字符数组,又叫字符串

        //字符串数组:数组内存放的元素是字符数组,数组套数组,所以字符串数组是一个二维的数组

        //字符数组

        char string1[6] = {'a', 'p', 'p', 'l', 'e', ''};

        //字符串

        char string2[6] = "apple";

        //字符串数组

        char string3[3][7] = {"apple", "xiaomi", "nokia"};    

  • memset(a,0,sizeof(a))的作用是把数组a清零,在string.h中定义。
  • 为了避免输出多余空格,设置一个标志变量first,可以表示当前要输出的变量是否是第一个。第一个变量前不应当有空格,但其他变量都有。
  • 在“scanf(“%s”, s)”中,不要在s前面加&号。如果是字符串数组s[maxn][maxl]/char *s[],可以用“scanf(“%s”, s[i])”读取第i个字符。注意,“scanf(“%上,s”)”遇到空白字符会停下来。如果输入是“2357”,那么实际上s只保存了5个字符(不要
    忘记了还有一个结束标记“”) 。
  • 善用常量数组往往能简化代码。定义常量数组时无需指明大小,编译器会计算。
  • 标志变量和常量数组大法好!
  • 由于ASCII码表中大写字母、 小写字母和数字都是连续的,如果ch是大写字母,则ch-'A'就是
    它在字母表中的序号(A的序号是0B的序号是1,依此类推);类似地,如果ch是数字,
    ch-'0'就是这个数字的数值本身(例如'5'-'0'=5)。
  • 头文件ctype.h中定义的isalphaisdigitisprint等工具可以用来判断字符
    的属性,而touppertolower等工具可以用来转换大小写。 如果ch是大写字母,则ch-'A'就是
    它在字母表中的序号(A的序号是0B的序号是1,依此类推);类似地,如果ch是数字,
    ch-'0'就是这个数字的数值本身。
  •  字典序:字典在字典中的顺序,一般,对于2个字符串,从第一个字符开始比较,当某一个字符不同时,该位置字符较小的串字典序较小,(eg:abc < bcd),如果其中一个字符串已经没有更多字符,但另一个字符串还没结束,则较短的字符串字典序较小,(eg:hi < history) 字典序的概念可以推广到任意序列(eg:1,2,4,7 < 1,2,5)
  • 求余算法可以有效降低程序的冗杂度,增强程序的可读性,特别是对一系列周期循环结构(比如循环队列),效果拔群。
  • http://blog.csdn.net/akof1314/article/details/4391119 取模的周期性
  • 1. 模运算是取余运算(记做 % 或者 mod),具有周期性的特点。 m%n的意思是n除m后的余数, 当m递增时m%n呈现周期性特点, 并且n越大,周期越长,周期等于n。

        0 % 20 = 0,1 % 20 = 1, 2 % 20 = 2, 3 % 20 = 3, ..., 19 % 20 = 19

       20 % 20 = 0,21 % 20 = 1,22 % 20 = 2,23 % 20 = 3, ...,39 % 20 = 19

设f(x)=x除以a的余数(a>0),则f(x)的周期为a(这里指最小的周期),取值从0,1,2,3,4,5,…,a按周期性变化。
举个例子f(x)=x除以7的余数,则
x=0 f(x)=0
x=1 f(x)=1
x=2 f(x)=2
x=3 f(x)=3
x=4 f(x)=4
x=5 f(x)=5
x=6 f(x)=6
x=7 f(x)=0
x=8 f(x)=1
x=9 f(x)=2
x=10 f(x)=3
x=11 f(x)=4
x=12 f(x)=5
x=13 f(x)=6
x=14 f(x)=0
x=15 f(x)=1
x=16 f(x)=2
x=17 f(x)=3
x=18 f(x)=4
x=19 f(x)=5
x=20 f(x)=6

 2. 如果 m % n = r,那么可以推出如下等式
             m = k * n + r (k为大于等于0的整数, r <= m)

3. 同余式, 表示正整数a,b对n取模,它们的余数相同,记做 a ≡ b mod n或者a = b (mod n)。

    根据2的等式可以推出 a = kn + b 或者 a - b = kn
    证明:   ∵ a = k1 * n + r1
                    b = k2 * n + r2
               ∴ a - b = (k1 - k2) * n + (r1 - r2)
                  a = k * n + (r1 - r2) + b
              ∵ a, b对n取模同余,r1 = r2
              ∴ a = k * n + b (k = k1 - k2)
4. 模运算规则, 模运算与基本四则运算有些相似,但是除法例外。其规则如下
    (a + b) % n = (a % n + b % n) % n            (1)
    (a - b) % n = (a % n - b % n) % n              (2) 
    (a * b) % n = (a % n * b % n) % n             (3)

 a% n = ((a % n)b) % n                             (4)

  • 同余函数是周期函数.对于同余函数,除数就可以认为是它的一个周期.关于7同余就是除以7所得的余数相同。同余函数有这么个说法。 至于取余,虽然说具有周期性,但它只是运算,是不是函数不清楚。

  • 有关模取问题:便于解决由最大下标位置移到到0下标时的越界处理。

    例:假设有MAXQSIZE=60(0~59)的一个数组,存储一个满循环队列Q
    队列为空时,初始化Q.front=Q.rear=0
    队列为满时:Q.front=0,Q.rear=59
    ps:这里我们可以探讨为什么要对MAXQSIZE取余求模,详如下:
    如果不取余:Q.rear+1=59+1=60,数组中最大下标为59而无60显然不取余是不对的
    取余后:(Q.rear+1)%MAXQSIZE=(59+1)%60=60%60=0,而Q.front=0,因此可以构成判断。

  • 队列取模,你想想取模是什么意思嘛,比如 % n,小于n的数字,都没影响不是吗?那到n的时候,一取模,就又回到0的位置了,所以数组的第一位是0,其实还有这么一个好处。 循环队列就是在固定大小的数组上实现队列,你可以把它想像成一个圆桌,标上0 - n-1,如果不是循环队列的话,你不停加数字,加到n-1的时候,就不能动了,没位置了,哪怕前面0-k已经走光了,但是不循环的话,那一块就浪费在那里。

因为循环队列是一个环,而这个环在达到末尾的时候再挪到下一个的时候就应该指到初始位置了。而取余这个操作可以满足一个数一直加但是最终结果一直在0和被除数之间循环的要求。
  举个例子,比如说一个长度为6的循环队列:
   0-1-2-3-4-5-
  比如说我要加进去8个数字0-7,每个位置一个数字。那么数字0(第1个数字)就在队列0的位置、数字1在队列中1的位值 ... 数字5在队列5的位置上。那么数字6呢?按照循环队列的要求,5的下一个位置是0,但是怎么才能根据已知条件(第n个数字和队列长度6)来求出这个0呢 那就要用到取余了。
   6(第7个数字)%6(队列长度) = 0 那么这个6 就放在0 的位置上

  继续,
   7(第8个数字)%6(队列长度) = 1 那么这个7 就放在1 的位置上

  现在比如说你有许多个数字要放进一个长度为 L 的循环队列中, 那么第n个数字要放在队列中的位置x就是
   x = ( n - 1 ) % L
  总结一下取余的目的就是为了让一个公差为1的递增序列变为在一个从0到L范围内循环的数列。(http://wenda.so.com/q/1481238043725563)

循环队列中 当对头出队列 队尾进队列 存在front的值大于rear的情况
此时rear-front 的值就为负的  而加上Maxsize后 就刚好补过来
   假设1:Maxsize=5     rear=0, front=4,  rear是指向队尾的下一个单元 也就是现在的rear指的单元没有存放数据因为front=4,若是front=0 就不是这种情况。 此时的队列长度1 ,如果不采用
       Length=(rear - front + Maxsize) % Maxsize的方法  得到错误的结果是 rear-front = -4 而采用刚才的算法就真好是 1。
   假设2:Maxsize=5   rear=3, front=0, 此时的对长是3,  Length=(rear - front + Maxsize) % Maxsize算的的结果也是3。相当 Length = rear - front + 0


    所以, 之所以在rear-front后面加上Maxsize是为了避免假设1 当中的情况产生, 而,后面取余 是为了在避免假设1:的基础上去避免假设2:的产生。 综合来说,单存在假设1 可以不要取余,单存在假设2 在计算队长的时候可以什么都不要,只要rear-front 即可。

  • 作为数组下标,i经常代表当前考虑的位置,或者与另一个下标j一起表示当前考虑子串的起点和终点。
  • 数组和字符串往往意味着大数据量,而处理大数据量经常遇到访问非法内存的错误。        适当把数组空间定义的较大,特别是不清楚数组开多大时,只要内存够用,开大一点没关系。在数组和字符串处理程序中,下标的计算是极为重要的。 
  • 理解字符编码对正确使用字符串是极其重要的,算法竞赛中涉及的一般是ASCII表中的可打印字符。
  • 二维数组一般和 打表联系在一起。
  • 需要输入多组数据,要把需要重新计数的变量在最后清空(为0/-1等等)。或者把要复位的变量定义在while循环里边并初始化为0
  • 乘以2也可以表示为<<1 意思是左移一位 左移4位就是*2^4.<<的优先级没有减法高;
  • 除以2也可以表示为>>1意思是右移一位 右移4位就是/2^4.
    • 把小写字母变成大写:ctype.h的toupper(c)返回c的大写形式;c-‘a'+‘A’把小写变成大写;ctype.h的isalpha(c)判断c是否为大写字母或者小写字母。
    • 1.相遇问题概念:
      两个运动物体作相向运动或在环形跑道上作背向运动,随着时间的发展,必然面对面地相遇,这类问题叫做相遇问题。它的特点是两个运动物体共同走完整个路程。小学数学教材中的行程问题,一般是指相遇问题。 
      2.相遇问题根据数量关系可分成三种类型:求路程,求相遇时间,求速度。 
      3.相遇问题解决所用到的基本关系式如下: 相遇问题公式:
      总路程=(甲速+乙速)×相遇时间 
      相遇时间=总路程÷(甲速+乙速) 
      另一个速度=甲乙速度和-已知的一个速度
      1.追击问题的概念:
      追及问题的地点可以相同(如环形跑道上的追及问题),也可以不同,但方向一般是相同的。由于速度不同,就发生快的追及慢的问题。 
      2.追及问题公式:根据速度差、距离差和追及时间三者之间的关系,常用下面的公式: 
      距离差=速度差×追及时间 
      追及时间=距离差÷速度差 
      速度差=距离差÷追及时间 
      速度差=快速-慢速 
      3.解题的关键是在互相关联、互相对应的距离差、速度差、追及时间三者之中,找出两者,然后运用公式求出第三者来达到解题目的。
    • 一、1.break语句通常用在循环语句和开关语句中。当break语句用于开关语句switch中时,可使程序跳出switch而执行switch以后的语句;如果没有break语句,则将成为一个死循环而无法退出。

      2.当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环后面的语句,通常break语句总是与if语句联在一起。即满足条件时便跳出循环。当检测到满足某个条件时,强行结束循环。在循环中,break只是结束其所在层的循环,对外层循环没有影响。

    • 二、continue语句的作用是跳过本循环中剩余的语句而强制执行下一次循环。continue语句只用在for、while、do-while等循环体中,常与if条件语句一起使用,用来加速循环。continue语句与break语句不同,在循环体内遇到continue语句时,将跳过本层循环体内continue语句之后的部分循环体,并开始下一轮循环,即只结束本轮循环。continue语句也通常和if语句配合使用,以控制在特定的条件下,仅执行循环体的一部分。需要注意的是,使用continue和使用break类似,它只能控制本层循环,并不影响外层循环。

    • break就相当于退学,continue则相当于跳级。
    • 存储复合型数据类型的时候,有时候基本数据类型无法满足现实中的变量描述,比如一个人有年龄int、身高float、姓名string/char*等等属性,所以你在描述一个人的属性时就不能用单一的基本数据类型来描述,于是便有了结构体
    • 一般在非数组,输出一个个的情况下,选择初始值当最值,把后输入的值与初始值比较,若比初始值更能胜任就替换;也可以把初始值设为一个极大极小(+/- INF)或者不可能的数(-1),在把后面每个数与其比较,注意是每个数而不是初始值后面的数。
    • ( a&1 )==0?  " a是偶数 " : " a是奇数 "
    • 1<<len == 2^len(len=4, 1<<4 == 2^4==16  => 1<<len==2^len)
      1.   int v = readint(len);//取得一个单位的编码,由二进制转化为十进制  
      2.  if (v == (1 << len) - 1)break;//1<<len==2^len 这里的意思是你的编码全为1的话,如v='1111' (len=4)则退出  
      这里的意思是你的编码全为1的话,如v='1111' (len=4)。(2^0+2^1+2^2+2^3==1+2+4+8==15)
    • 根据日期求是一年中周几的计算公式:int ans=(Day +1+ 2*Month + 3*(Month+1)/5 + Year + Year/4 - Year/100 + Year/400) % 7
  • 在ACM中  一丁点错误就足以造成你的失败

    关于 double float 的精确度问题     

    double比float 精绝度要高     精确到小数点6位左右

    在在代码中对浮点数据类型直接使用== 、<= 、>=、 !=等运算符进行比较都是不正确的。

    正确的方法应该是 将其差或和于小数进行比较   通常与10^6 比较

    浮点数与零的比较:

    等于0关系:  fabs(i)<=1e-6

    大于0关系:  i>1e-6

    小于0关系:  i<1e-6

    在三角形中  任意2边大于第三边   a+b>c  如果直接这样写  会造成无法AC       如果这样写 a+b-c>1e-6   则是可以AC的 

    所以在做题过程中注意  对于浮点型千万不要直接比较

    • int main()
      {
      int a[10]={1,2,3,4,5};
      do{
      printf("%d%d%d%d%d ",a[0],a[1],a[2],a[3],a[4]);
      }while(next_permutation(a,a+5));
      return 0;
      }//全排列打表12345-54321

    • 简而言之,Prime算法背后是日拱一卒的保守主义的世界观,在算法开始时不假设已知全部信息,而将图分为一个已知的A集合,(包含最小生成树)以及一个B集合(将要加入最小生成树)的集合。而Kruskal算法则要求对所有边按照权值进行排序,然后再重头开始贪心的构建生成树,背后是建构主义的世界观。
    • 如果对一个二维图的处理和整行整列有关系的话,那么多半可以用二分图进行处理,二分图的题其实大多数都不是难在匈牙利算法上,而是在图的建立上。
原文地址:https://www.cnblogs.com/Roni-i/p/7157955.html