ACM经典算法之数学问题模板

转自:http://blog.sina.com.cn/s/blog_93d2ceba010145a9.html


一、(精度计算——大数阶乘)

语法:int result=factorial(int n);

参数:

n:

n 的阶乘

返回值:

阶乘结果的位数

注意:

 

 

本程序直接输出n!的结果,需要返回结果请保留long a[]

 

需要 math.h

源程序:

 

 

int factorial(int n)
{
long a[10000];
int i,j,l,c,m=0,w; 

a[0]=1; 
for(i=1;i<=n;i++)
    { 
    c=0; 
    for(j=0;j<=m;j++)
        { 
        a[j]=a[j]*i+c; 
        c=a[j]/10000; 
        a[j]=a[j]000; 
    } 
    if(c>0) {m++;a[m]=c;} 


w=m*4+log10(a[m])+1;
printf("\n%ld",a[m]); 
for(i=m-1;i>=0;i--) printf("%4.4ld",a[i]);
return w;


二、 (精度计算——乘法(大数乘小数))

语法:mult(char c[],char t[],int m);

参数:

c[]:

被乘数,用字符串表示,位数不限

t[]:

结果,用字符串表示

m:

乘数,限定10以内

返回值:

null

注意:

 

 

需要 string.h

源程序:

 

 

void mult(char c[],char t[],int m)
{
    int i,l,k,flag,add=0;
    char s[100];
    l=strlen(c);
    for (i=0;i
        s[l-i-1]=c[i]-'0'; 

    for (i=0;i
           {
           k=s[i]*m+add;
           if (k>=10) {s[i]=k;add=k/10;flag=1;} else {s[i]=k;flag=0;add=0;}
           }
    if (flag) {l=i+1;s[i]=add;} else l=i;

    for (i=0;i
        t[l-1-i]=s[i]+'0';
    t[l]='\0';
}


三、

(精度计算——乘法(大数乘大数))

 

语法:mult(char a[],char b[],char s[]);

参数:

a[]:

被乘数,用字符串表示,位数不限

b[]:

乘数,用字符串表示,位数不限

t[]:

结果,用字符串表示

返回值:

null

注意:

 

 

空间复杂度为 o(n^2)

 

需要 string.h

源程序:

 

 

void mult(char a[],char b[],char s[])
{
    int i,j,k=0,alen,blen,sum=0,res[65][65]={0},flag=0;
    char result[65];
    alen=strlen(a);blen=strlen(b); 

    for (i=0;i
    for (j=0;j

    for (i=alen-1;i>=0;i--)
        {
            for (j=blen-1;j>=0;j--) sum=sum+res[i+blen-j-1][j];
            result[k]=sum;
            k=k+1;
            sum=sum/10;
        }

    for (i=blen-2;i>=0;i--)
        {
            for (j=0;j<=i;j++) sum=sum+res[i-j][j];
            result[k]=sum;
            k=k+1;
            sum=sum/10;
        }
    if (sum!=0) {result[k]=sum;k=k+1;}

    for (i=0;i
    for (i=k-1;i>=0;i--) s[i]=result[k-1-i];
    s[k]='\0';

    while(1)
        {
        if (strlen(s)!=strlen(a)&&s[0]=='0') 
            strcpy(s,s+1);
        else
            break;
        }
}


四、 (精度计算——加法)

语法:add(char a[],char b[],char s[]);

参数:

a[]:

被乘数,用字符串表示,位数不限

b[]:

乘数,用字符串表示,位数不限

t[]:

结果,用字符串表示

返回值:

null

注意:

 

 

空间复杂度为 o(n^2)

 

需要 string.h

源程序:

 

 

void add(char a[],char b[],char back[])
{
    int i,j,k,up,x,y,z,l;
    char *c;
    if (strlen(a)>strlen(b)) l=strlen(a)+2; else l=strlen(b)+2;
    c=(char *) malloc(l*sizeof(char));
    i=strlen(a)-1;
    j=strlen(b)-1;
    k=0;up=0;
    while(i>=0||j>=0)
        {
            if(i<0) x='0'; else x=a[i];
            if(j<0) y='0'; else y=b[j];
            z=x-'0'+y-'0';
            if(up) z+=1;
            if(z>9) {up=1;z%=10;} else up=0;
            c[k++]=z+'0';
            i--;j--;
        }
    if(up) c[k++]='1';
    i=0;
    c[k]='\0';
    for(k-=1;k>=0;k--)
        back[i++]=c[k];
    back[i]='\0';


五、(精度计算——减法)

语法:sub(char s1[],char s2[],char t[]);

参数:

s1[]:

被减数,用字符串表示,位数不限

s2[]:

减数,用字符串表示,位数不限

t[]:

结果,用字符串表示

返回值:

null

注意:

 

 

默认s1>=s2,程序未处理负数情况

 

需要 string.h

源程序:

 

 

void sub(char s1[],char s2[],char t[])
{
    int i,l2,l1,k;
    l2=strlen(s2);l1=strlen(s1);
    t[l1]='\0';l1--;
    for (i=l2-1;i>=0;i--,l1--)
        {
        if (s1[l1]-s2[i]>=0) 
            t[l1]=s1[l1]-s2[i]+'0';
        else
            {
            t[l1]=10+s1[l1]-s2[i]+'0';
            s1[l1-1]=s1[l1-1]-1;
            }
        }
    k=l1;
    while(s1[k]<0) {s1[k]+=10;s1[k-1]-=1;k--;}
    while(l1>=0) {t[l1]=s1[l1];l1--;}
loop:
    if (t[0]=='0') 
        {
        l1=strlen(s1);
        for (i=0;i
        t[l1-1]='\0';
        goto loop;
        }
    if (strlen(t)==0) {t[0]='0';t[1]='\0';}
}


六、(任意进制转换)

语法:conversion(char s1[],char s2[],long d1,long d2);

参数:

s[]:

原进制数字,用字符串表示

s2[]:

转换结果,用字符串表示

d1:

原进制数

d2:

需要转换到的进制数

返回值:

null

注意:

 

 

高于9的位数用大写'A'~'Z'表示,2~16位进制通过验证

源程序:

 

 

void conversion(char s[],char s2[],long d1,long d2)
{
    long i,j,t,num;
    char c;
    num=0;
    for (i=0;s[i]!='\0';i++)
        {
        if (s[i]<='9'&&s[i]>='0') t=s[i]-'0'; else t=s[i]-'A'+10;
        num=num*d1+t;
        }
    i=0;
    while(1)
        {
        t=num�;
        if (t<=9) s2[i]=t+'0'; else s2[i]=t+'A'-10;
        num/=d2;
        if (num==0) break;
        i++;
        }
    for (j=0;j
        {c=s2[j];s2[j]=s[i-j];s2[i-j]=c;}
    s2[i+1]='\0';
}


七、(最大公约数、最小公倍数)


语法:resulet=hcf(int a,int b)、result=lcd(int a,int b)

参数:

a:

int a,求最大公约数或最小公倍数

b:

int b,求最大公约数或最小公倍数

返回值:

返回最大公约数(hcf)或最小公倍数(lcd)

注意:

 

 

lcd 需要连同 hcf 使用

源程序:

 

 

int hcf(int a,int b)
{
    int r=0;
    while(b!=0)
        {
        r=a%b;
        a=b;
        b=r;
        }
    return(a);

lcd(int u,int v,int h)
{
    return(u*v/h);
}


八、(组合序列)


语法:m_of_n(int m, int n1, int m1, int* a, int head)

参数:

m:

组合数C的上参数

n1:

组合数C的下参数

m1:

组合数C的上参数,递归之用

*a:

1~n的整数序列数组

head:

头指针

返回值:

null

注意:

 

 

*a需要自行产生

 

初始调用时,m=m1、head=0

 

调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);

源程序:

 

 

void m_of_n(int m, int n1, int m1, int* a, int head) 

    int i,t; 
    if(m1<0 || m1>n1) return

    if(m1==n1) 
        { 
        for(i=0;i
        cout<<'\n'; 
        return
        } 
    m_of_n(m,n1-1,m1,a,head); // 递归调用 
    t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;
    m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用 
    t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t;


九、(快速傅立叶变换(FFT))


语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],int l,int il);

参数:

pr[n]:

输入的实部 

pi[n]:

数入的虚部

n,k:

满足n=2^k

fr[n]:

输出的实部

fi[n]:

输出的虚部

l:

逻辑开关,0 FFT,1 ifFT

il:

逻辑开关,0 输出按实部/虚部;1 输出按模/幅角 

返回值:

null

注意:

 

 

需要 math.h

源程序:

 

 

void kkfft(pr,pi,n,k,fr,fi,l,il) 
int n,k,l,il; 
double pr[],pi[],fr[],fi[]; 
{
    int it,m,is,i,j,nv,l0; 
    double p,q,s,vr,vi,poddr,poddi; 
    for (it=0; it<=n-1; it++) 
        {
         m=it; is=0; 
        for (i=0; i<=k-1; i++) 
            {j=m/2; is=2*is+(m-2*j); m=j;}
        fr[it]=pr[is]; fi[it]=pi[is]; 
        } 
    pr[0]=1.0; pi[0]=0.0; 
    p=6.283185306/(1.0*n); 
    pr[1]=cos(p); pi[1]=-sin(p); 
    if (l!=0) pi[1]=-pi[1]; 
    for (i=2; i<=n-1; i++) 
        {
       p=pr[i-1]*pr[1];
       q=pi[i-1]*pi[1]; 
        s=(pr[i-1]+pi[i-1])*(pr[1]+pi[1]); 
        pr[i]=p-q; pi[i]=s-p-q; 
        } 
    for (it=0; it<=n-2; it=it+2) 
        {
       vr=fr[it]; vi=fi[it]; 
        fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1]; 
        fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; 
        } 
    m=n/2; nv=2; 
    for (l0=k-2; l0>=0; l0--) 
        {
        m=m/2; nv=2*nv; 
        for (it=0; it<=(m-1)*nv; it=it+nv) 
            for (j=0; j<=(nv/2)-1; j++) 
                {
               p=pr[m*j]*fr[it+j+nv/2]; 
                q=pi[m*j]*fi[it+j+nv/2]; 
                s=pr[m*j]+pi[m*j]; 
                s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); 
                poddr=p-q; poddi=s-p-q; 
                fr[it+j+nv/2]=fr[it+j]-poddr; 
                fi[it+j+nv/2]=fi[it+j]-poddi; 
                fr[it+j]=fr[it+j]+poddr; 
                fi[it+j]=fi[it+j]+poddi; 
                } 
        } 
    if (l!=0) 
        for (i=0; i<=n-1; i++) 
            {
           fr[i]=fr[i]/(1.0*n); 
            fi[i]=fi[i]/(1.0*n); 
            } 
    if (il!=0) 
            for (i=0; i<=n-1; i++) 
            {
           pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]); 
            if (fabs(fr[i])<0.000001*fabs(fi[i])) 
                {
               if ((fi[i]*fr[i])>0) pi[i]=90.0; 
                else pi[i]=-90.0; 
                } 
            else 
                pi[i]=atan(fi[i]/fr[i])*360.0/6.283185306; 
            } 
    return


十、(Ronberg算法计算积分)


语法:result=integral(double a,double b);

参数:

a:

积分上限

b:

积分下限

function f:

积分函数

返回值:

f在(a,b)之间的积分值

注意:

 

 

function f(x)需要自行修改,程序中用的是sina(x)/x

 

需要 math.h

 

默认精度要求是1e-5

源程序:

 

 

double f(double x)

    return sin(x)/x; //在这里插入被积函数 
}

double integral(double a,double b) 

    double h=b-a; 
    double t1=(1+f(b))*h/2.0;
    int k=1; 
    double r1,r2,s1,s2,c1,c2,t2; 
loop: 
    double s=0.0; 
    double x=a+h/2.0; 
    while(x
        { 
        s+=f(x); 
        x+=h; 
        } 
    t2=(t1+h*s)/2.0;
    s2=t2+(t2-t1)/3.0;
    if(k==1)
      { 
        k++;h/=2.0;t1=t2;s1=s2;
        goto loop; 
        } 
    c2=s2+(s2-s1)/15.0; 
    if(k==2){ 
        c1=c2;k++;h/=2.0; 
        t1=t2;s1=s2; 
        goto loop; 
        } 
    r2=c2+(c2-c1)/63.0; 
    if(k==3){ 
        r1=r2; c1=c2;k++; 
        h/=2.0; 
        t1=t2;s1=s2;
        goto loop; 
        } 
    while(fabs(1-r1/r2)>1e-5){ 
        r1=r2;c1=c2;k++;
        h/=2.0; 
        t1=t2;s1=s2; 
        goto loop; 
        } 
    return r2;


十一、(行列式计算)

对角线展开:
|a1 b1|  =a1b2-a2b1
|a2 b2|  

|a1 b1 c1|
|a2 b2 c2|=a1b2c3+b1c2a3+c1a2b3-a3b2c1-b3c2a1-c3a2b1
|a3 b3 c3|

降阶展开(适合高阶行列式)
如三阶行列式 按第一阶展开
|a b c|
|d e f |=a×|e f|-b×|d f|+c×|d e| 
|g h i |      |h i|      |g i|     |g  h|
按中阶展开
以上行列式=e×|a c|-d×|b c|-f×|a b|
                        |g  i|     |h  i|    |g h|
其他行列式计算相仿

语法:result=js(int s[][],int n)

参数:

s[][]:

行列式存储数组

n:

行列式维数,递归用

返回值:

行列式值

注意:

 

 

函数中常数N为行列式维度,需自行定义

源程序:

 

 

int js(s,n) 
int s[][N],n; 
{
    int z,j,k,r,total=0; 
    int b[N][N]; 
    if(n>2)
        {
        for(z=0;z
            {
            for(j=0;j
                 for(k=0;k
                        if(k>=z) b[j][k]=s[j+1][k+1];  else b[j][k]=s[j+1][k]; 
            if(z%2==0) r=s[0][z]*js(b,n-1);  
            else r=(-1)*s[0][z]*js(b,n-1); 
            total=total+r; 
            } 
        } 
    else if(n==2)
       total=s[0][0]*s[1][1]-s[0][1]*s[1][0]; 
    return total; 


十二、(求排列组合数)


语法:result=P(long n,long m); / result=long C(long n,long m);

参数:

m:

排列组合的上系数

n:

排列组合的下系数

返回值:

排列组合数

注意:

 

 

符合数学规则:m<=n

源程序:

 

 

long P(long n,long m)
{
    long p=1;
    while(m!=0)
        {p*=n;n--;m--;}
    return p;

long C(long n,long m)
{
    long i,c=1;
    i=m;
    while(i!=0)
        {c*=n;n--;i--;}
    while(m!=0)
        {c/=m;m--;}
    return c;



你可能感兴趣的:(ACM,大数高精度,数论,组合数学,c基础编程,杂题)