zoukankan      html  css  js  c++  java
  • ACM Steps_Chapter Two_Section3

    A + B Problem II

    /*
    分析:对于此题做法有两种:其一,使2字符串的中的字符数字减去'0',
    逐个相加大于等于10的可以使本位减10,下一位自增1,后面的处理就非常简单了;
    其二,便是读入字符串后先让各个字符减'0',一一对应存入整形数组中;之后再相加。
    对于2种方法大致是相同的,都要从后面向前加,逢十进位,以及数组初始化均要初始为0,
    一边方便运算。
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int main()
    {
        int n,i,len1,len2,j,k,pi,t,flag;
        char str1[1010],str2[1010];
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            int a[1200]={0};
            flag=0;
            printf("Case %d:\n",i);
            scanf("%s%s",str1,str2);//以字符串形式读入
            len1=strlen(str1);
            len2=strlen(str2);
            printf("%s + %s = ",str1,str2);
            j=len1-1;
            k=len2-1;
            pi=0;
            while(j>=0&&k>=0)//开始相加
            {
                if(a[pi]+(str1[j]-'0')+(str2[k]-'0')>=10)//相加后大于10的
                {
                    a[pi]=a[pi]+(str1[j]-'0')+(str2[k]-'0')-10;
                    a[pi+1]++;
                }
                else
                    a[pi]=a[pi]+(str1[j]-'0')+(str2[k]-'0');
                pi++;
                k--;
                j--;
            }
            if(j>=0)
            {
                for(t=j;t>=0;t--)
                {
                    a[pi]=a[pi]+(str1[t]-'0');
                    pi++;
                }
            }
            else if(k>=0)
            {
                for(t=k;t>=0;t--)
                {
                    a[pi]=a[pi]+str2[t]-'0';
                    pi++;
                }
            }
            else if(a[pi]!=0)//对于位数相同2个数加后最高位大于10的
                pi++;
            for(t=pi-1;t>=0;t--)
            {
                if(a[t]==0&&flag==0)//处理一次啊前导0,估计属于无用的一步
                    continue;
                else
                {
                    flag=1;
                    printf("%d",a[t]);
                }
               
            }
            printf("\n");
            if(i!=n)//对于2组之间加空行的情况
                printf("\n");
        }
        return 0;   
    }
    

    Big Number

    /*
    我们有公式, log10(n!)=(0.5*log(2*PI*n)+n*log(n)-n)/log(10) , 
    这里利用了 log10 (N)=ln(N)/ln(10);
    
    公式的名字是 斯特林公式
    */
    
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include<string.h>
    #include<time.h>
    #define PI 3.1415926
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int digits,n;
            scanf("%d",&n);
            if(n==0)  //没有也过了..
            {
                printf("1\n");
                continue;
            }
            digits=(int)((0.5*log(2*PI*n)+n*log(n)-n)/log(10));
            printf("%d\n",digits+1);   //加1是必须的。
        }
        return 0;
    }
    

    Hat's Fibonacci

    /*
    用二维数组模拟大数加法,每一行表述一个数,每一行的一个元素可以代表n位数,
    这个可以根据自己的需要自己定义。
    其他的就和正常的加法一样了,注意进位处理。
    */
    #include <iostream>
    #include <stdio.h>
    using namespace std;
    int s[7500][670];
    void solve(){
        s[1][1] = 1;s[2][1] = 1;
        s[3][1] = 1;s[4][1] = 1;
        int i,j,k=0;
        for(i = 5;i<7500;i++)
        {
    		for( j = 1;j<=670 ;j++)
        	{
            	k += s[i-1][j]+s[i-2][j]+s[i-3][j]+s[i-4][j];
            	s[i][j] = k%10000;
            	k = k/10000;
        	}
        	while(k)
        	{
            	s[i][j++] = k%10000;
            	k = k/10000;
        	}
    	}
    }
    int main()
    {
        int n,i,j;
        solve();
        while(cin>>n)
        {
            for(i = 670; i>=1;i--)
            if(s[n][i]!=0)break;
            printf("%d",s[n][i]);
            for(j = i-1;j>=1;j--)
            printf("%04d",s[n][j]);
            printf("\n");
        }
    }
    

    How Many Trees?

    /*
    Catalan数的解法
    
    Catalan数的组合公式为 Cn=C(2n,n) / (n+1);
    此数的递归公式为  h(n ) = h(n-1)*(4*n-2) / (n+1)
     小数解
    对于50以下的小数解来说,使用数组就可以完成,代码如下:
    #include<iostream>
    using namespace std;
    int main()
    {
         long long  int a[101][101],i,j,n;
        for (i=0; i<101; i++)    //利用数组求 Catalan数
            a[i][0] = 1;
        for (i=1; i<101; i++)                    
        {
            for (j=1; j<=i; j++)   
                a[i][j] = a[i][j-1] + a[i-1][j];   
        }
        while (cin>>n)   
        {     
            cout<<a[n][n]<<endl;
        }
        return 0;
    }
     大数解
    对于大数来说,就应该使用下面的大数算法。
    使用的公式为:h(n)  = h(n-1)*(4*n-2)/n+1;
    */
    #include<iostream>
    using namespace std;
    #define MAX 100
    #define BASE 10000
    void multiply(int a[],int Max,int b)  //大数乘法
    {
        int i,array=0;
        for (i=Max-1; i>=0; i--)   
        {
            array+=b*a[i];
            a[i] = array%BASE;
            array /= BASE;   
        }
    }
     
    void divide(int a[], int Max, int b)  //大数除法
    {
        int i,div=0;
        for (i=0;i<Max; i++)   
        {
            div = div*BASE + a[i];
            a[i] = div / b;
            div %= b;
        }
    }
    int main()
    {
        int a[101][MAX],i,j,n;
        memset(a[1],0,MAX*sizeof(int));
        for (i=2,a[1][MAX-1]=1; i<101; i++)
        {
            memcpy(a[i],a[i-1],MAX*sizeof(int));      //h[I] = h[i-1];  
            multiply(a[i],MAX,4*i-2);               //h[i] *= (4*i-2);
            divide(a[i],MAX,i+1);                  //h[i] /= (i+1);
        }
        while (cin>>n)   
        {
            for (i=0; i<MAX && a[n][i]==0; i++);  //去掉数组前为0的数字。
            cout<<a[n][i++];             //输出第一个非0数
            for (; i<MAX; i++)   
                printf("%04d",a[n][i]);       //输出后面的数,并每位都保持5位长度
            cout<<endl;
        }
        return 0;
    }
    

    Buy the Ticket

    /*
    推導過程如下:
    m個人拿50,n個人拿100
    1、如果n > m,那麼排序方法數為0,這一點很容易想清楚
    2、現在我們假設拿50的人用‘0’表示,拿100的人用‘1’表示。
     如果有這麼一個序列0101101001001111。
     當第K個位置出現1的個數多餘0的個數時就是一個不合法的序列了
     假設m=4,n=3的一個序列是:0110100 。顯然,它不合法,現在我們把它稍微變化一下:
     把第二個1(這個1前面的都是合法的)後面的所有位0變成1,1變成0.
     就得到0111011這個序列1的數量多餘0的數量,顯然不合法,
     但現在的關鍵不是看這個序列是不是合法的
     關鍵是:他和我們的不合法序列0110100成一一對應的關係。
     也就是說任意一個不合法序列(m個0,n個1),都可以由另外一個序列(n-1個0和m+1個1)得到。
     另外我們知道,一个序列要麼是合法的,要麼是不合法的
     所以,合法序列數量 = 序列總數量 - 不合法序列的總量
     序列總數可以這樣計算 m+n個位置中,選擇n個位置出來填上1,所以是C(m+n,n).
     不合法序列的數量就是: m+n個位置中,選擇m+1個位置出來填上1,所以是C(m+n,m+1).
     然後每個人都是不一樣的,所以需要全排列m! * n!.
     所以最後的公式為:( C(m+n,n) - C(m+n,m+1) ) * m! * n!
     化簡即為:(m+n)!*(m-n+1)/(m+1)
    
    推廣:
     如果原來有p張50元的話,那麼不合法的序列的數量應該是:
     任意一個不合法序列(m個0,n個1),都可以由另外一個序列(n-1個0和m+1+p個1)得到,
     所以是m+n個位置中,選擇m+1+p個位置,出來填上1所以是C(m+n,m+1+p),接下來簡化就不推了
     */
    
    
    //卡特蘭數的應用
    //公式如下:(m+n)! * (m-n+1) / (m+1) 
    #include <iostream>
    #include <string>
    using namespace std;
    int fact[205][100];
    int res[100];
    void multiply(int a[],int b)   //大數乘小數 
    {
         int i,temp = 0;
         for(i = 99;i >= 0;i--)
         {
               temp += b * a[i];
               a[i] = temp % 10000;
               temp /= 10000;
         } 
    }
    void Fact()  //求階乘
    {
         fact[0][99] = fact[1][99] = 1;
         for(int i = 2;i <= 200;i++)
         {
                 memcpy(fact[i],fact[i-1],100*sizeof(int));
                 multiply(fact[i],i);
         }
    }
    void divide(int a[],int b)       //大數除小數 
    {
         int i,temp = 0;
         for(i = 0;i < 100;i++)
         {
               temp = temp*10000 + a[i];
               a[i] = temp / b;
               temp %= b;
         }
    }
    void output(int a[])       //輸出 
    {
         int i = 0;
         while (i < 100 && a[i] == 0)
               i++;     //去掉前導的0 
         printf("%d",a[i++]);
         while(i < 100)
                 printf("%04d",a[i++]);
         putchar('\n');
         
    }
    int main()
    {
        int m,n,t = 1;
        Fact();
        while(cin >> m >> n , m+n)
        {
                  printf("Test #%d:\n",t++);
                  if(n > m)
                  {
                       puts("0");
                       continue;
                  }
                  memcpy(res,fact[m+n],100*sizeof(int));
                  multiply(res,m-n+1);
                  divide(res,m+1);
                  output(res);
        }
        return 0;
    }
    

    Count the Trees

    /*
    卡特蘭數的公式C(n) = ( 4n - 2 ) * C( n-1)   / (n+1)
    這個相當於在卡特蘭數的基礎上乘以一個n!,即:
    n!*C(n) = n! * (4n - 2) * C(n-1) / (n+1) = (4n - 2) * n * ((n-1) * C(n-1))  /  (n+1)
    另H(n) = n! * C(n),則有: H(n) = (4n - 2) * n * H(n-1) / (n+1)
    H(1) = 1*C(1) = 1
    所以推導公式如下:
    H(1) = 1;
    H(n) = n * (4n - 2) * H(n-1) / (n+1)
    */
    #include<iostream> 
    using namespace std;
    int a[101][1001] = {0};
    int main()
    {
        int n,i,j,k,b[101],len;
        b[1] = len = 1;
        a[1][0] = 1;
        for(i = 2;i < 101;i++)
        {
              for(j = 0;j < len;j++)    // 大數乘法
                    a[i][j] = (4*i-2) * i * a[i-1][j];
              for(k = j = 0;j < len;j++)
              {
                    a[i][j] += k;
                    k = a[i][j] / 10;
                    a[i][j] %= 10;
              }
              while(k) 
              {
                     a[i][len++] = k % 10;
                     k /= 10;
              }
              for(k = 0,j = len-1;j >= 0;j--)     //大數除法 
              {
                     a[i][j] += k*10;
                     k = a[i][j] % (i+1);
                     a[i][j] /= (i+1); 
              }
              while(!a[i][len-1])
                     len--;
              b[i] = len;
        }
        while(cin >> n,n)
        {
                  for(i = b[n]-1;i >= 0;i--)
                        cout << a[n][i];
                  cout << endl;
        }
        return 0;
    } 
    

    Game of Connections

    /*
    catalan数高精度
    
    公式:c(n+1)=2*(2*n+1)*c(n)/(n+2)
    
    高精度除法从高位开始模拟现实除法步骤求得商
    */
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    
    using namespace std;
    
    const int maxN=110;
    const int maxM=1010;
    
    int a[maxN][maxM];
    int tmp[maxM];
    
    int main(){
        a[0][0]=1;
        for(int i=0;i<maxN;++i){
            int k=2*(2*i+1);
            for(int j=0,c=0;j<maxM;++j){
                int s=a[i][j]*k+c;
                c=s/10;
                a[i+1][j]=s%10;
            }
            k=maxM;
            int cnt=0;
            while(!a[i+1][--k]);
            for(int s=0;k>=0;--k){
                s=10*s+a[i+1][k];
                tmp[cnt++]=s/(i+2);
                s%=(i+2);
            }
            for(int j=0;j<maxM;++j){
                if(j<cnt)
                    a[i+1][j]=tmp[cnt-j-1];
                else
                    a[i+1][j]=0;
            }
        }
        int n;
        while(cin>>n,n!=-1){
            int i=maxM;
            while(!a[n][--i]);
            for(;i>=0;i--)
                cout<<a[n][i];
            cout<<endl;
        }
        return 0;
    }
    

    小兔的棋盘

    /*
    令h(0) = 1,h(1) = 1,卡特蘭數滿足遞歸式:
    
    h(n) = h(0) * h(n-1) + h(1) * h(n-2) + ... + h(n-1) * h(0) (其中n>=2),
    這是n階遞推關係
    還可以化簡為1階遞推關系:
    h(0) = 1;
    h(n) = (4n-2) / (n+1) * h(n-1) (n > 1) ;
    該遞推關係的解為:h(n) = c(2n,n)/(n+1) (n = 1,2,3,...)
    */
    //h(0) = 1;
    //h(n) = (4n-2) * h(n-1) / (n+1) (n > 1) ;
    //但是此題中如果直接用a[i] = (4*i-2)*a[i-1]/(i+1);會溢出 
    //所以直接用这个式子
    //h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0) 
    #include<iostream> 
    using namespace std;
    __int64 a[36] = {0};
    int main()
    {
        int i,j,n,t=1;
        a[0] = 1;
        for(i = 1;i < 36;i++)
        {
              a[i] = 0;
              for(j = 0;j <= i;j++)
                    a[i] += a[j] * a[i-j-1]; 
        }
        while(cin >> n && n != -1)
                  cout << t++ << " " << n << " " << a[n]*2 << endl;
        return 0;
    }
    


  • 相关阅读:
    Javascript进阶(7)---函数参数
    Django连接mssql(SqlServer)
    ORM查询
    Django-Model操作数据库
    Django去操作已经存在的数据库
    如何设置CentOS 7获取动态及静态IP地址
    nginx代理设置
    Django+Linux+Uwsgi+Nginx项目部署文档
    nginx的安装部署
    Django项目在linux系统中虚拟环境部署
  • 原文地址:https://www.cnblogs.com/oldoldb/p/3311323.html
Copyright © 2011-2022 走看看