zoukankan      html  css  js  c++  java
  • 读算法竞赛入门

    读算法竞赛入门

    经典算法与思想

    TIPs

    • 在代码中获得圆周率pi的比较好的方式是使用库math.h中的三角函数:4.0atan(1.0),4.0acos(1.0)等
    • sacanf的返回值是成功输入的变量的个数,例如如果scanf("%d%d",&a,&b)成功执行则返回2。
    • #ifdef LOCAL...,freopen("test.in","r",stdin);,freopen("test.out","w",stdout)
    • 有些问题的输出不会溢出,但其运算过程很可能会发生溢出,所以这点需要注意。
    • 在linux系统中栈大小没有保存在可执行文件中,不过可以使用指令ulimit来改变栈的大小;在windows系统中栈大小保存在可执行文件中,使用gcc编译时可以使用指令-Wl,--stack=16777216来指定栈的大小。所以一般将较大的数组保存在main函数之外或者使用堆中的空间。

    使用递归逆序输出数组

    代码:

    #include<stdio.h>
    #include<string.h>
    void reverse_str(const char*str){
     int len = strlen(str);
     if(len == 0){
      //在基准情形中执行的一些动作没有“重复性”
      return;
     }
     else{
      reverse_str(str+1);
      putchar(*(str));//“递归”之后需要做一些事情
     }
    }
    
    int main(){
     char str[] = "abcdefg";
     reverse_str(str);
    }
    

    aabb完全平方数(p17)

    注意floor在程序中的作用

    #include<stdio.h>
    #include<math.h>
    
    int main(){
     for(int i=1;i<10;i++){
      for(int j=0;j<10;j++){
       int a = i*1100 + j*11;
       //int b = sqrt(a); //如果这里b是int型则floor的使用就没有意义了
       double b = sqrt(a);
       if(floor(b+0.5) * floor(b+0.5) == a)printf("%d
    ",a);
      }
     }
    }
    

    开关灯问题 uva 10110

    直接明了的方式是使用数组模拟这些动作,但效率不好。这些灯的开关是有规律的,开关被触发奇数次则电灯是开着的,如果被触发偶数次则是关着的,奇数偶数只与电灯编号因数个数的奇偶性有关。

    一个整数的因数必然是成对出现的,例如15=1*15、15=3*5;9=1*9、9=3*3。可以发现只有完全平方数的因数是奇数个,只要判断电灯编号是否是完全平方数就可以判断电灯的状态。

    注意

    当前题目中n的取值范围是2^32-1则必须使用无符号int,因为long在很多平台上与int取值范围相同,所以使用long时也必须是无符号的。

    打印蛇形数

    右上角的初始值、循环内的两种判断、内存空间的初始化

    注意事项:在堆中分配的内存一般需要使用memset主动设置为0,否则可能都是乱码;

    最长回文词 uva 11151

    核心思想是枚举,但枚举也是有方向的:向右,或向两侧

    竖式问题(p87)

    一般而言没有效率要求的问题上,怎样简单怎样求解。

    相同问题的统一处理。

    问题:找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合

    解法:

    注意函数的使用方法:sprintf(buffer,"%d%d%d%d%d",a,b,c,d,e);strchar(string,char)

    总结:

    一些相同的操作可以合并然后做统一的处理,例如本问题中的“子集”问题,这些字符串合并之后再进行处理可以简化编码。

    素数求解问题

    使用i*i = x 来判断x是否是素数是有问题的,因为当x很大时i*i可能溢出:

    比例说当判断2147395601是否是素数时,i需要大于46340,可46340*46340将溢出。

    相对比较简单且不易溢出的方法:

    int is_prime(int x){
    	assert(x>0);
    	//int prime = 1;  //多此一举
    	if(x == 1) return 0;
    	else{
    		int m = floor(sqrt(x) + 0.5); //必须加0.5
    		for(int i = 2;i<m;i++){
    			if(x%i == 0){
    				//prime = 0;
    				//break;  //直接返回0即可
    				return 0;
    			}
    		}
    	}
    	//return prime; //直接返回1即可
    	return 1;
    }
    

    WERTYU uva 10082

    使用常量数组有时可以简化逻辑

    善用常数字符串将简化操作(p94),isdigit(int) ,isprint(int), isalpha(int) toupper(int) tolower() in ctype.h

    #include<stdio.h>
    
    char s[55]="`1234567890-=QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./";  
    int main()  
    {  
        int i,c;  
        while((c=getchar())!=EOF)  
        {  
    		//直接遍历,获得 i,这样可以简化逻辑(不用写for循环体)
            for(i=1;s[i]&&s[i]!=c;i++); 
            if(s[i]) putchar(s[i-1]); //字符串的结尾标志是'' 
            else putchar(c);  
        }  
        return 0;  
    }  
    

    周期串 uva 455

    首先要注意的是 对0取余可能使程序假死,所以 m%0 使不能使用的,这点编译与执行的过程中都不会报错,但程序的执行结果是错误的

    m%n 可以看做是 m - (int)(m/n)*n,前提是m和n均为正整数

    小学生算术 uva10035

    注意进位

    #include<stdio.h>
    
    int main(){
     int a,b;
     int c = 0;
     int ans = 0;
     while(1){
      scanf("%d%d",&a,&b);
      if(a == 0 && b == 0)break;
      c = 0;
      for(int i = 0;i<9 && a>0 && b>0;i++){
       //c = (a%10 + b%10 + c)/10 ;
       c = (a%10 + b%10 + c)>9?1:0;//判断要快于除法
       ans += c;
       a = a/10;b = b/10;
      }
      if(ans == 0)
       printf("No carry operation.
    ");
      else{
       printf("%d carry operations.
    ",ans);
      }
     }
    }
    

    阶乘的精确值 uva623

    n<=500,打印n!的精确值

    字母重排

    如何确定两个单词的组成相同?是迭代判断?显然效率太低,最好的办法是先排序这两个单词,然后再比较排序后的字符串。

    C标准库函数qsort:

    void qsort( void *buf, //指向数据
    			size_t num, //需要比较num项数据
    			size_t size, //每项数据的大小
    			int (*compare)(const void *, const void *) );
    //对于compare的要求,第一项大于第二项则返回正值;等于返回0;小余返回负值。
    

    cantor数表 uva264

    首先确定位置.判断在第几斜列有两种思想:

    • 迭代法,迭代n:1+2+...+n来判断m在第n列
    • 用数学法判断:n<=1/2 *k(k+1),通过解不等式来获得n,这样更快

    猜数字游戏(理解的不是很透彻)p99

    循环列表

    如何实现字符串数组的循环访问(使用整数取余运算)

    生成元问题

    查表思想、也许运算的结果不会溢出,但运算的中间值可能溢出,这样依旧会出错

    TEX中的引号

    注意事项:getchar的返回值为int型,因为EOF是int型;逐字符读取的函数有getchar(),int fgetc(FILE *stream)

    参考代码:

    // UVa272 Tex Quotes
    // Rujia Liu
    #include<stdio.h>
    int main() {
      int c, q = 1;
      while((c = getchar()) != EOF) {
        if(c == '"') { printf("%s", q ? "``" : "''"); q = !q; }
        else printf("%c", c);
      }
      return 0;
    }
    

    回文词与镜像词

    • 注意:
      * 首先问题是如何判断回文与镜像

    Circular Sequence

    • 注意两个字符串以字典序比较大小的方法,容易出的逻辑错误是只比大小不判相等。
      for(int i = 0; i < n; i++)
        if(s[(p+i)%n] != s[(q+i)%n])
          return s[(p+i)%n] < s[(q+i)%n];
    

    UVA 679 Dropping Balls

    • 两种典型的思想:“枚举”,递归思想

    思想篇

    暴力求解

    暴力求解也有一定的技巧,例如给定n,求abcde/fghij=n的表达式,其中a~j为0~9,如果穷举abcde和fghij则需要10!次,但如果将原式写成abcde=n*fghij,只穷举fghij再判断abcde是否满足要求则可以使穷举次数减少到不到10000次。

    最大连续和问题

    • 给出一个实数序列,A1,A2,......An,求最大连续和 ;这里有一个思想可以降低算法的时间复杂度:连续子序列之和等于两个前缀和之差

    最一般的解法就是穷举法,从A1开始进行穷举,算法的复杂度是O(n^3);但先求前缀和可以使算法的复杂度降低为O(n^2)。

  • 相关阅读:
    inet_ntoa解析
    日语常用计算机词汇
    Visual Studio 2012 : error LNK2026: module unsafe for SAFESEH image
    android异常总结四 :Unexpected text found in layout file: """
    android异常总结三 :R文件丢失
    android异常总结二 :This text field does not specify an inputType or a hint
    android异常总结一 :reslayoutOtherActivity.xml: Invalid file name: must contain only [a-z0-9_.]
    Win8下配置java环境
    CUDA实例练习(五):两数相加
    CUDA实例练习(四):矩阵转置
  • 原文地址:https://www.cnblogs.com/jiahu-Blog/p/6443607.html
Copyright © 2011-2022 走看看