高精度问题

高精度求N!

题目描述
用高精度方法,求N!的精确值(N以一般整数输入)。
输入
输入一个整数n( 1<= n <= 350)
输出
输出n!
样例输入
10
样例输出
3628800

思路
题目最大要求350!,因此基本的数据类型都会溢出,选择高精度算法,利用数组来存一个数的各个位数,最后输出即可。

代码

#include <bits/stdc++.h>
using namespace std;
 
int a[1000];
 
int main(){
    int n,i,j,c=0,p;
    cin>>n;
    if(n==1)
        cout<<"1";
    else{
        a[0]=1;									//令个位为1 
        for(i=2;i<=n;++i){						//阶乘 
            c=0;								//初始化进位 
            for(j=0;j<1000;++j){				//倒着存 
                p=a[j]*i+c;						//高精度乘法
                a[j]=p%10;
                c=p/10;							//处理进位 
            }
        }
        for(i=999;i>=0;--i)						//去除后导0 
            if(a[i]>0)
                break;
        for(j=i;j>=0;--j)						//倒序输出
            cout<<a[j];
    } 
     
    return 0;
} 

求A/B高精度值

题目描述
计算A/B的精确值,设A,B是以一般整数输入,计算结果精确小数后20位
(若不足20位,末尾不用补0) 。
输入
输入2个普通的整数A和B
输出
输出A/B的值,保留20位小数,如果不足20位,末尾不用补0,格式见样例
样例输入
【样例1】
4 3
【样例2】
6 5
样例输出
【样例1】
4/3=1.33333333333333333333
【样例2】
6/5=1.2
提示
输出结果如果小数点后只有一个0,需要输出X.0

思路
本题只需要开一个数组,把小数点后面的数存到数组里,逐位输出即可。

代码

#include <bits/stdc++.h>
using namespace std;
int s[21];
 
int main(){
    int a,b,i,j;
    cin>>a>>b;
    cout<<a<<"/"<<b<<"="<<a/b<<".";				//输出整数部分与小数点 
    int p=a%b*10;								//模拟除法,对余数进行处理 
    for(i=1;i<=20;++i){							//模拟小数点后的20位 
        s[i]=p/b;								//将每次的商存入数组 
        p=p%b*10;								//更新余数并处理为下一个被除数 
    }
    cout<<s[1];									//小数点后的第1位一定输出 
    for(i=20;i>1;i--)							//后19位去除末尾为0 
        if(s[i]!=0)
            break;
    for(j=2;j<=i;++j)							//正序输出 
        cout<<s[j];
    return 0;
}

阶乘和(sum)

题目描述
已知正整数N(N<=100),设S=1!+2!+3!+…N!。其中"!"表示阶乘,即N!=123*……(N-1)N,如:3!=123=6。请编程实现:输入正整数N,输出计算结果S的值。
输入
输入一个整数n( 1<= n<=100)
输出
输出s的值
样例输入
4
样例输出
33

思路
题目最大涉及到100!,并要求求和,因此必须用高精度算法来解决,开两个数组a,sum,a数组算从1~n每项的阶乘,sum数组对这些阶乘进行求和,即a数组进行高精度乘法,sum数组进行高精度加法,最后输出sum数组即可。

代码

#include <bits/stdc++.h>
using namespace std;
 
int a[1000],sum[1000];
 
void by(int n){								//高精度乘法 
    int i,j,c=0,p;
    a[0]=1;					
    for(i=2;i<=n;++i){
        c=0;
        for(j=0;j<1000;++j){
            p=a[j]*i+c;
            a[j]=p%10;
            c=p/10;
        }
    } 
}
void add(){									//高精度加法 
    int c=0,i,p;
    for(i=0;i<1000;++i){
        p=sum[i]+a[i]+c;
        sum[i]=p%10;
        c=p/10;
    } 
}
 
int main(){
    int n,i,j;
    cin>>n;
    for(i=1;i<=n;++i){
        memset(a,0,sizeof(a));				//对a数组每次都要初始化 
        by(i);								//阶乘 
        add();								//加 
    }
    for(i=999;i>=0;--i)						//去除后导0 
        if(sum[i]>0)
            break;
    for(j=i;j>=0;--j)						//逆序输出 
        cout<<sum[j];  
    return 0;
}

高精度求积(MULTIPLY)

题目描述
输入两个高精度非负整数M和N(M和N均小于100位)。
输入
输入两个高精度非负整数M和N(M和N均小于100位)。
输出
求这两个高精度数的积。
样例输入
36
3
样例输出
108

思路
M,N均小于100位,定义三个数组a,b,c,a数组表示m,b数组表示n,c数组表示两数的积,把c数组逐位输出即可。注:m,n均以字符串的形式读入

代码

#include <bits/stdc++.h>
using namespace std;
string m,n;
int a[110],b[110],c[221];
 
int main(){
    int i,d,e,p=0,j,k;
    cin>>m>>n;
    d=m.size();							//m的位数 
    e=n.size();							//n的位数 
    for(i=d-1;i>=0;--i)
        a[d-1-i]=m[i]-'0';				//逆序存m 
    for(i=e-1;i>=0;--i)
        b[e-1-i]=n[i]-'0';				//逆序存n 
    k=0;								//初始化进位k 
    for(i=0;i<d;++i){					//高精度乘法 
        for(j=0;j<e;++j){
            p=a[i]*b[j]+k;
            c[i+j]+=p%10;
            k=p/10;
            if(c[i+j]>=10){					//进位 
                c[i+j+1]+=c[i+j]/10;
                c[i+j]=c[i+j]%10;
            } 
        }
        while(k){							//最高位进位 
            c[i+e]+=k%10;
            k=k/10;
            e++;							//改变位数 
        }
    }
    for(i=220;i>=0;--i)						//去除后导0 
        if(c[i]!=0)
            break;
    if(i<0)									//如果c数组全为0,则积为0 
        cout<<"0";
    else{
        for(j=i;j>=0;--j)					//逆序输出为积 
            cout<<c[j];
    }
    return 0;
}

回文数

题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数56,将56加65(即把56从右向左读),得到121是一个回文数。
又如:对于十进制数87:
STEP1:87+78 = 165
STEP2:165+561 = 726
STEP3:726+627 = 1353
STEP4:1353+3531 = 4884
在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。
写一个程序,给定一个N,2≤N≤10,N=16)进制数M(100位之内),求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出Impossible!
输入
两行,分别是N,M。
输出
STEP=ans
样例输入
10
87
样例输出
STEP=4

思路
判断30次,如果30次均为非回文数,那么退出循环,输出Impossible!;对于每一次判断,如果是回文数,则退出循环,输出STEP=ans,如果不是回文数,使用高精度加法,更新m的值,继续循环判断。

代码

#include <bits/stdc++.h>
using namespace std;
int n;
string m;
 
bool huiwen(string n){									//判断回文数 
    bool f=true;
    int i;
    for(i=0;i<n.size()/2;++i)
        if(n[i]!=n[n.size()-1-i])
            f=false;
    return f;
}
int num(char c){										//字符转数字 
    if(c>='0'&&c<='9')    return c-'0';
    else{
        switch(c){
            case 'A':return 10;
            case 'B':return 11;
            case 'C':return 12;
            case 'D':return 13;
            case 'E':return 14;
            case 'F':return 15;
        }
    }
}
char zim(int c){									 //数字转字符 
    if(c>=0&&c<=9)    return c+'0';
    else{
        switch(c){
            case 10:return 'A';
            case 11:return 'B';
            case 12:return 'C';
            case 13:return 'D';
            case 14:return 'E';
            case 15:return 'F';
        }
    }
}
string add(string a){								//高精度加法 
    int l=a.size(),i,k,d,p,q,x;
    string b=a,s="";								//初始化字符串b,s 
    reverse(a.begin(),a.end());
    d=0;											//初始化进位d 
    p=0;
    q=0;
    for(i=0;i<l;++i){
        p=num(a[i])+num(b[i])+d;
        q=p%n;
        d=p/n;
        s=zim(q)+s;									//在字符串头部插入字符 
    }
    while(d){										//判断最高位是否进位 
        x=d%10;
        d=d/10;
        s=zim(x)+s;									//在字符串头部插入字符 
    }
    return s;
}
 
int main(){
    int i;
    cin>>n;
    cin>>m;
    for(i=0;i<=30;++i){
        if(huiwen(m))								//判断回文 
            break;	
        m=add(m);									//更新m 
    }
    if(i>30) cout<<"Impossible!";
    else cout<<"STEP="<<i;
    return 0;
}

汉诺双塔

给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。

现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为2n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。

输入
一个正整数n,表示在AA柱上放有2n个圆盘。
输出
一个正整数, 为完成上述任务所需的最少移动次数An。
样例输入
【输入样例1】
1
【输入样例2】
2
样例输出
【输出样例1】
2
【输出样例2】
6
提示
【限制】
对于50%的数据,1≤n≤25
对于100%的数据,1≤n≤200
【提示】
设法建立An与An−1的递推关系式

思路
汉诺双塔移动的次数为pow(2,n+1)-2,也可看作F[N]=F[N-1]+2+F[N-1]=2*F[N-1]+2;由于需要处理的数据范围太大,必须使用高精度乘法与高精度加法。定义两个数组a与sum,用a数组模拟乘法,每次×2求可移动次数,把每次的可移动次数求和为总移动次数sum。

代码

#include <bits/stdc++.h>
using namespace std;
int a[205],sum[205];
 
 
int main(){
    int n,i,j,d,p,k,x;
    cin>>n;
    a[200]=1;									//初始化a数组最后一位 
    for(i=1;i<=n;++i){
        d=0;									//初始化进位 
        for(j=200;j>0;--j){						//高精度乘法 
            p=a[j]*2+d;
            a[j]=p%10;
            d=p/10;
        }
        k=0;									//初始化进位 
        for(j=200;j>0;--j){						//高精度加法 
            x=a[j]+sum[j]+k;
            sum[j]=x%10;
            k=x/10;
        }
    }
    for(i=1;i<=200;++i){						//去除前导0 
        if(sum[i]!=0)
            break;
    }
    for(j=i;j<=200;++j)							//正序输出 
        cout<<sum[j];
    return 0;
}

天使的起誓

题目描述
Tenshi非常幸运地被选为掌管智慧之匙的天使。在正式任职之前,她必须和其他新当选的天使一样要宣誓。
宣誓仪式是每位天使各自表述自己的使命,他们的发言稿放在n个呈圆形排列的宝盒中。这些宝盒按顺时针方向被编上号码1,2,…,n-1,n。
一开始天使们站在编号为n的宝盒旁。她们各自手上都有一个数字,代表她们自己的发言稿所在的盒子是从1号盒子开始按顺时针方向的第几个。例如:有7个盒子,如果Tenshi手上的数字为9,那么她的发言稿所在的盒子就是2个。现在天使们开始按照自己手上的数字来找发言稿,先找到的就可以先发言。
Tenshi一下子就找到了,于是她最先上台宣誓:“我将带领大家开启Noi之门……” Tenshi宣誓结束后,陆续有天使上台宣誓。可是有一位天使找了好久都找不到她的发言稿,原来她手上的数字m非常大,她转了好久都找不到她想找的宝盒。
请帮助这位天使找到她想找的宝盒编号。
输入
第一行为正整数n,第二行为正整数m,其中n,m满足2<=n<=108,2<=m<=101000
输出
只有一行(包括换行符),即天使想找的宝盒的编号。
样例输入
【输入样例1】
7
9
【输入样例2】
11
108
样例输出
【输出样例1】
2
【输出样例2】
9

思路
简单的剩余定理,取余即可,注:余数为0,要输出n,更新余数。另:数据量太大,以字符串的形式读入

代码

#include <bits/stdc++.h>
using namespace std;
 
 
int main(){
    int n,l,i,s=0;
    string m;
    cin>>n>>m;
    l=m.size();								//m位数 
    for(i=0;i<l;++i)
        s=(s*10+m[i]-'0')%n;				//更新余数 
    if(s==0)    cout<<n;
    else cout<<s;
    return 0;
}

附加

递归求一个数的倒序数

#include <bits/stdc++.h>
using namespace std;
 
int f(int n){
    if(n>=0&&n<10)    printf("%d",n);
    else{
        printf("%d",n%10);
        return f(n/10);
    }
} 
 
int main(){
    int n;
    cin>>n;
    f(n);
    return 0;
}

递归进制转换:十进制转八进制

#include <bits/stdc++.h>
using namespace std;
 
int f(int n){
    if(n/8==0)
        return n;
    else return f(n/8)*10+n%8;
}
 
int main(){
    int n;
    cin>>n;
    cout<<f(n);
    return 0;
}

递归:双色汉诺塔问题

设A、B、C是3 个塔座。开始时,在塔座A 上有一叠共n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动1 个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至A,B,C 中任一塔座上。

试设计一个算法,用最少的移动次数将塔座A 上的n个圆盘移到塔座B 上,并仍按同样顺序叠置。

对于给定的正整数n,编程计算最优移动方案。

输入
由文件hanoi.in给出输入数据。第1 行是给定的正整数n。
输出
将计算出的最优移动方案输出到文件hanoi.out。文件的每一行由一个正整数k和2个字符c1和c2组成,表示将第k个圆盘从塔座c1移到塔座c2上
样例输入
3
样例输出
1 A B
2 A C
1 B C
3 A B
1 C A
2 C B
1 A B
提示
n<10

#include <bits/stdc++.h>
using namespace std;
void hanot(int n,char a,char b, char c){
    if(n>0){
        hanot(n-1,a,c,b);
        cout<<n<<' '<<a<<' '<<b<<endl;
        hanot(n-1,c,b,a);
    }
}
 
int main(){
    int n;
    cin>>n;
    hanot(n,'A','B','C');
    return 0;
}
  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值