算法初级_3 :函数与递归

来源:互联网 发布:wear it on 编辑:程序博客网 时间:2024/06/05 07:18

牛顿迭代法

  • x=x0f(x0)f(x0)
#include<iostream>#include <math.h>using namespace std;float Calc(float a){    if(a<1e-6)  //10^{-6}表示很小的数        return 0;    float x=a/2;    float t=a;    while(fabs(x-t)>1e-6){        t=x;        x=(x+a/x)/2;    }    return x;}int main(int argc,char* argv[]){    for(int i=0;i<=10;i++)        cout<<Calc((float)i)<<'\n';    return 0;}

宏(文字替换)

  • define

内联函数

  • inline

callatz猜想

  • 给定正整数N,若为偶数,则N被更新为N/2;否则被更新为3*N+1;
    问多少次N可以变成1
 // 3n+1// [问题描述]  // 考虑如下的序列生成算法:从整数 n 开始,如果 n 是偶数,把它除以 2;如果 n 是奇数,把它乘 3 加  // 1。用新得到的值重复上述步骤,直到 n = 1 时停止。例如,n = 22 时该算法生成的序列是:  //  // 22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1  //  // 人们猜想(没有得到证明)对于任意整数 n,该算法总能终止于 n = 1。这个猜想对于至少 1 000 000  // 内的整数都是正确的。  //  // 对于给定的 n,该序列的元素(包括 1)个数被称为 n 的循环节长度。在上述例子中,22 的循环节长度  // 为 16。输入两个数 i 和 j,你的任务是计算 i 到 j(包含 i 和 j)之间的整数中,循环节长度的最大  // 值。  //  // [输入]  // 输入每行包含两个整数 i 和 j。所有整数大于 0,小于 1 000 000。  //  // [输出]  // 对于每对整数 i 和 j,按原来的顺序输出 i 和 j,然后输出二者之间的整数中的最大循环节长度。这三  // 个整数应该用单个空格隔开,且在同一行输出。对于读入的每一组数据,在输出中应位于单独的一行。  //  // [样例输入]  // 1 10  // 100 200  // 201 210  // 900 1000  //  // [样例输出]  // 1 10 20  // 100 200 125  // 201 210 89  // 900 1000 174  //  // [解题方法]  // 计算每个数的循环节长度,求给定区间的最大值。  //  #include <iostream>  using namespace std;  #define min(a, b) ((a) <= (b) ? (a) : (b))  #define max(a, b) ((a) >= (b) ? (a) : (b))  #define MAXSIZE 1000000  int cache[MAXSIZE];  // 计算循环节长度。  int counter(long long number)  {      if (number == 1)          return 1;      // 模 2 计算可用与计算代替,除 2 计算可用右移计算代替。      if (number & 1)          number += (number << 1) + 1;      else          number >>= 1;      // 若 number 在缓存范围内则根据情况取用。      if (number < MAXSIZE )      {          if (!cache[number])              cache[number] = counter(number);          return 1 + cache[number];      }      return 1 + counter(number);  }  int main(int ac, char *av[])  {      //      // memset(cache, 0, sizeof(cache));      //      int first, second, start, end;      while (cin >> first >> second)      {          // 得到给定范围的上下界。          start = min(first, second);          end = max(first, second);          // 查找最大步长值。          int result = 0, steps;          for (int i = start; i <= end; i++)              if ((steps = counter(i)) > result)                  result = steps;          // 输出。          cout << first << " " << second << " " << result << endl;      }      return 0;  }  

棋子染色

//循环染色问题////[问题描述]//用红蓝两色将围城一圈的8个棋子染色,规定://若两个方案,通过旋转的方式可以重合,则算一种// 一共有多少染色方案?//// [算法]//0,1表示染色方案,8个棋子对应8个二进制//旋转等于,循环左移一次得到y,则x和y属于相同的类别// 1. 若y<x. 删除x// 2. 若y>x 删除y//(删除大者)////复杂度:O(N)#include<iostream>#include<list>#include<algorithm>using namespace std;int RotateShiftLeft(int x, int N){    int high=(x>>(N-1));     x &=((1<<(N-1))-1); //保留最高的符号位    x<<=1;    x|=high;    return x;}int Polya(int N,list<int> &answer){    int i,j;    int k1,k2;    int m=(1<<N); //10000000    try{    int *p=new int[m]; //记录每种方案    fill(p,p+m,1);    for(i=0;i<m;i++)  //遍历所有染色方案    {        if(p[i]==1)  // 尚未删除        {            k1=i;            for(j=0;j<=N;j++)            {                k2=RotateShiftLeft(k1,N);                if(k2==i)                    break; // 说明完成了循环                if(k2>i) //后面的k2无效                    p[k2]=0;                else                 {                    p[i]=0;  //i无效                    break;                }                 k1=k2;            }        }    }    for(i=0;i<m;i++)    {        if(p[i]==1)            answer.push_back(i);    }    delete[] p;    return (int)answer.size();    }catch( bad_alloc &e)    {        return -1;    }}int main(int ac ,char *av[]){    int number;    list<int> res;  //存储方案    while(cin>>number){        if(number>2)            cout<<Polya(number,res)<<endl;        else             cout<<"input error"<<endl;    }}//循环左移一位//http://www.cnblogs.com/alex4814/archive/2011/09/08/2171862.html//a = 01111011,循环左移2位的正确结果是: b=11101101//b=a>>(8-2);//a=a|b;// a=(a>>(8-2))|(a<<2)//直接表达式//循环左移n (a >> (N - n)) | (a >> n)//循环右移n (a << (N - n)) | (a >> n)

矩阵乘法

1)采用Strassen算法作递归运算,需要创建大量的动态二维数组,其中分配堆内存空间将占用大量计算时间,从而掩盖了Strassen算法的优势

2)于是对Strassen算法做出改进,设定一个界限。当n<界限时,使用普通法计算矩阵,而不继续分治递归。需要合理设置界限,不同环境(硬件配置)下界限不同

3)矩阵乘法一般意义上还是选择的是朴素的方法,只有当矩阵变稠密,而且矩阵的阶数很大时,才会考虑使用Strassen算法。


大整数乘法

  • karatsuba算法
    http://www.cnblogs.com/starrybird/p/4445566.html

  • 算法

    1. 取大整数xy的长度较大者的一半,记为k
    2. x=x1Mk+x0;
      y=y1Mk+y0
      =>xy=(x1Mk+x0)(y1Mk+y0)
      =x1y1M2k+(x1y0+x0y1)Mk+x0y0
      =x1y1M2k+((x1+x0)(y1+y0)x1y1+x0y0)Mk+x0y0
  • 复杂度:
    O(nlog3)=O(n1.585)

0 0