//5.6.1大整数的存储
struct bign{
int a[1000];
int len;
};
//输入大整数时,先用字符串读入,然后把字符串另存为至bign结构体
bign change(char str[])
{
bign a;
a.len = strlen(str);//bign的长度就是字符串的长度
for(int i = 0;i<a.len;i++){
a.d[i] = str[a.len - i - 1] - '0';//字符串倒着赋值给d[]数组
}
return a;
}
//比较两个bign变量的大小,先判断len大小,若相等,则从高位到低位遍历
int compare(bign a,bign b)//比较a/b,a大、相等、a小分别返回1、0、-1
{
if(a.len > b.len) return 1;//a大
else if(a.len < b.len) return -1;
else
{
for(int i=a.len - 1;i >= 0;i--)//从高位往低位比较
{
if(a.d[i] > b.d[i]) return 1;//只要有一位a大,则a大
else if(a.d[i] < b.d[i]) return -1;
}
return 0;//两数相等
}
}
//1高精度加法
bign add(bign a,bign b)//高精度a+b
{
bign c;
int carry = 0;//carry是进位
for(int i=0;i<a.len || i<b.len;i++)//以较长的为界限,从低到高位加
{
int temp = a.d[i] + b.d[i] + carry;//两个对应位与进位相加
c.d[c.len++] = temp % 10;//个数位为该位结果
carry = temp / 10;//十位数为新的进位
}
if(carry != 0)//如果最后进位不为0,则直接赋值给结果的最高位
{
c.d[c.len++] = carry;
}
return c;
}
//完整A+B代码(非负整数)
#include <cstdio>
#include <cstring>
struct bign{
int d[1000];
int len;
bign(){
memset(d,0,sizeof(d));
len = 0;
}
};
bign change(char str[])//将整数转换为bign
{
bign a;
a.len = strlen(str);
for(int i=0;i<a.len;i++){
a.d[i] = str[a.len - i - 1] - '0';
}
return a;
}
bign add(bign a,bign b){//高精度a+b
bign c;
int carry = 0;//carry是进位
for(int i=0;i<a.len||i<b.len;i++){
int temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp%10;
carry = temp / 10;
}
if(carry != 0){
c.d[c.len++] = carry;
}
return c;
}
void print(bign a){//输出bign
for(int i=a.len - 1;i >= 0;i--){
printf("%d",a.d[i]);
}
}
int main()
{
char str1[1000],str2[1000];
scanf("%s%s",str1,str2);
bign a = change(str1);
bign b = change(str2);
print(add(a,b));
return 0;
}
//2.高精度减法
bign sub(bign a,bign b){//高精度a-b
bign c;
for(int i=0;i<a.len || i<b.len;i++){//以较长的为界限
if(a.d[i] < b.d[i]){//如果不够减
a.d[i+1]--;//向高位借位
a.d[i] += 10;//当前位加10
}
c.d[c.len++] = a.d[i] - b.d[i];//减法结果为当前位结果
}
while(c.len-1 >= 1 && c.d[c.len - 1] == 0){
//注意此处len-1,因为赋值时候用的c.len++,所以先赋值再++,数组最后一个数为c.d[len-1]
c.len--;//去除高位的0,同时至少保留一位最低位
}
return c;
}
//高精度与低精度的乘法:始终将低精度数作为一个整体看待
bign multi(bign a,bign b){//高精度乘法
bign c;
int carry = 0;//进位
for(int i = 0;i < a.len;i++){
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry != 0){//和加法不一样,乘法的进位可能不止一位,因此用while
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
//4.高精度与低精度的除法(注意最后一步减法后高位可能有多余的0,
//要忽视它们,但也要保证结果至少有一位数
bign divide(bign a,int b,int &r){//高精度除法,r为余数
bign c;
c.len = a.len;//被除数的每一位和商的每一位是一一对应的,因此先令长度相等
for(int i = a.len - 1;i >= 0;i--){//从高位开始
r = r * 10 + a.d[i];//和上一位遗留的余数组合
if(r < b) c.d[i] = 0;//不够除,该位为0
else{//够除
c.d[i] = r/b;//商
r = r % b;//获得新的余数
}
}
while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){
c.len--;//去除高位的0,同时至少保留一位最低位
}
return c;
}
Contest100000593 - 《算法笔记》5.6小节——数学问题->大整数运算
题目链接:http://codeup.cn/problem.php?cid=100000593&pid=0
//关于大整数与字符串的转化,字符串可以用char数组(C语言)与string(C++语言)
//之前print 返回类型错写成bign,结果程序死活过不去,后来改了就过了,真是玄学
//1949-Problem-A-a+b
//关于大整数与字符串的转化,字符串可以用char数组(C语言)与string(C++语言)
//之前print 返回类型错写成bign,结果程序死活过不去,后来改了就过了,真是玄学
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct bign{
int data[1050];
int len;
bign(){
memset(data,0,sizeof(data));
len = 0;
}
};
bign change(string str){
bign a;
// a.len = strlen(str);
a.len = str.size();
for(int i=0;i<a.len;i++){
a.data[a.len - i - 1] = str[i] - '0';
}
return a;
}
bign add(bign a,bign b){
bign c;
int carry=0;
for(int i=0;i<a.len || i<b.len;i++){
int temp = a.data[i] + b.data[i] + carry;
c.data[c.len++] = temp % 10;
carry = temp / 10;
}
if(carry != 0){
c.data[c.len++] = carry;
}
return c;
}
void print(bign a){
for(int i=a.len-1;i>=0;i--){
printf("%d",a.data[i]);
}
}
int main()
{
string str1,str2;
while(cin>>str1>>str2){
bign a = change(str1);
bign b = change(str2);
print(add(a,b));
cout<<endl;
}
return 0;
}
题目链接: http://codeup.cn/problem.php?cid=100000593&pid=1
//1917-Problem-B-N的阶乘
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct bign{
int data[5000];
int len;
bign(){
memset(data,0,sizeof(data));
len = 0;
}
};
bign change(string str){
bign a;
// a.len = strlen(str);
a.len = str.size();
for(int i=0;i<a.len;i++){
a.data[a.len - i - 1] = str[i] - '0';
}
return a;
}
bign multi(bign a,int b){//高精度乘法
bign c;
int carry = 0;//进位
for(int i = 0;i < a.len;i++){
int temp = a.data[i] * b + carry;
c.data[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry != 0){//和加法不一样,乘法的进位可能不止一位,因此用while
c.data[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
void print(bign a){
for(int i=a.len-1;i>=0;i--){
printf("%d",a.data[i]);
}
}
int main(){
int n;
while(cin>>n){
bign res;
res.data[0]=1; //注意初始化为1
res.len = 1;
for(int i=2;i<=n;i++)
{
res = multi(res,i);//注意函数返回类型,刚开始没有更新res,一直输出1
}
print(res);
cout<<endl;
}
return 0;
}
题目链接:http://codeup.cn/problem.php?cid=100000593&pid=2
//1922-Problem-C-浮点数加法
//仿照大整数思想,将浮点数与字符串转换,并将整数与小数部分分开存储与处理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct floatn{
int x[1000];
int y[1000];
int px;//整数部分指针
int py;//小数部分指针
floatn(){
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
px = 0;
py = 0;
}
};
floatn change(string str){//字符串浮点数存储到结构体相应数组中
floatn a;int flag = 1;
a.px=0,a.py=0;//整数、小数部分指针
for(int i=0;i<str.length();i++){
if(str[i] == '.'){
flag = 0;
continue;
}
if(flag) a.px++;//整数部分
else a.y[a.py++] = str[i] - '0';//小数部分正序存储
}
for(int i=0;i<a.px;i++){//整数部分顺序存储
a.x[a.px - i - 1] = str[i] - '0';
}
return a;
}
//浮点加法
floatn add(floatn a,floatn b)//高精度a+b
{
floatn c;
int carry = 0;//carry是进位
//小数部分相加
c.py = max(a.py,b.py);//注意小数部分计数指针的处理
int temp0 = 0;
for(int i=c.py-1;i>0;i--){
int temp = a.y[i] + b.y[i] + carry;
c.y[i] = temp % 10;//此处是c.y[i]
carry = temp / 10;
}
if(carry != 0)//如果最后进位不为0,则进位至小数位最高位y[0]
{
temp0 = carry;
}
//小数位次高位进位可能会影响小数位最高位和整数位最低位
carry= (a.y[0] + b.y[0] + temp0) / 10;
c.y[0] += (a.y[0] + b.y[0] + temp0) % 10;
while(!c.y[c.py-1]) c.py--;//小数部分坑:末尾相加为0不要输出,将py--
// carry = 0;
//整数部分相加
for(int i=0;i<a.px || i<b.px;i++){
int temp = a.x[i] + b.x[i] + carry;
c.x[c.px++] = temp % 10;
carry = temp / 10;
}
if(carry != 0)//如果最后进位不为0,则直接赋值给结果的最高位
{
c.x[c.px++] = carry;
}
return c;
}
void print(floatn a){//输出浮点数,注意整数倒序存储,小数顺序存储
for(int i=a.px-1;i>=0;i--){
printf("%d",a.x[i]);
}
printf(".");
for(int i=0;i<a.py;i++){
printf("%d",a.y[i]);
}
}
int main(){
int n;
while(cin>>n){
while(n--){
string str1,str2;
cin>>str1>>str2;
floatn z;
floatn x = change(str1);
floatn y = change(str2);
z = add(x,y);
print(z);
cout<<endl;
}
}
return 0;
}
题目链接: http://codeup.cn/problem.php?cid=100000593&pid=3
//1950-Problem-D-进制转换
//类似于辗转相除法将十进制转换为2进制,正序输入,除得余数倒序输出,注意乘以相应的权值
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int M,N;
string str;
while(cin>>M>>N>>str){
int in[1050],out[1050];//输入存放数组in,输出存放数组out
int len = str.length();
for(int i=0;i<len;i++){//将输入的字符串转化为数存放
if(str[i] >= '0' && str[i] <= '9') in[i] = str[i] - '0';
else in[i] = str[i] - 'A' + 10;
}
int index=0,sum=1;//数组下标指针与判停参数
while(sum){//辗转相除法获取out数组,期间将in[]数的还原和存储到out[]结合到一起了
sum = 0;
for(int i=0;i<len;i++){
sum += in[i] / N;//相除,更新sum,当in[]数组为0,sum为0停止
//本次循环里最后一位权重为1;当i==len-1时,数据还原完成,开始辗转相除取余,存入out[]
if(i == len - 1) out[index++] = in[i] % N;
else in[i+1] += (in[i] % N) * M;//乘以相应权重加到下一位,还原in[]的数
in[i] /= N;
}
}
if(index == 0){
cout<<0;
}
else{
for(int i=index-1;i>=0;i--){//倒叙输出输出数组
if(out[i] >= 0 && out[i] <= 9)
cout<<out[i];
else//注意字母的处理
cout<<(char)(out[i] + 'a' - 10);
}
}
cout<<endl;
}
return 0;
}
题目链接: http://codeup.cn/problem.php?cid=100000593&pid=4
//1951-Problem-E-大整数排序
//有时候大整数直接等价于字符串处理,特别是string类型的出现又花了这一流程
//当然,输入输出必须是配套的C++流处理
//bign此题并不合适,因为bign相当于string,但是这题是string数组
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
bool cmp(string x,string y){//排序规则
if(x.length() != y.length())//先比较长度
return x.length() < y.length();
else{
for(int i=0;i<x.length();i++){//长度相等从高位向低位比较各位上的数
if(x[i] != y[i])
return x[i] < y[i];//相等时顺序不变
}
}
}
int main()
{
int N;
string num[110];
while(cin>>N){
for(int i=0;i<N;i++){//输入多个大整数
cin>>num[i];
}
sort(num,num+N,cmp);
for(int i=0;i<N;i++){//输出
cout<<num[i]<<endl;
}
}
return 0;
}
题目链接: http://codeup.cn/problem.php?cid=100000593&pid=5
进制转换进阶题
//1952-Problem-F-10进制-VS-2进制
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
string str;
while(cin>>str){
int in[1010],temp[5010],out[1010];
int len = str.length();
for(int i=0;i<len;i++){
in[i] = str[i] - '0';
}
int index=0,sum=1;
while(sum){//输入数据in[]转换为2进制temp[]
sum = 0;
for(int i=0;i<len;i++){
sum += in[i]/2;
if(i == len-1) temp[index++] = in[i]%2;
else in[i+1] += (in[i]%2)*10;
in[i] /= 2;
}
}
if(index == 0){
cout<<0;
}
else{//二进制temp转换为out,temp[]逆序存储,则按存储顺序处理即可得逆序数
len = index,index=0,sum=1;
while(sum){
sum=0;
for(int i= 0;i<len;i++){
sum += temp[i] / 10;
if(i == len-1) out[index++] = temp[i]%10;
else temp[i+1] += (temp[i] % 10) * 2;
temp[i] /= 10;
}
}
for(int i=index-1;i>=0;i--){
cout<<out[i];
}
}
cout<<endl;
}
return 0;
}
大整数相当于一维的字符串问题,用C++的string类型与cin、cout简直很溜;bign大整数数据类型适用于一维特殊情况