HDU 1753 大明A+B(大数加法,数组模拟)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1753

Problem Description
话说,经过了漫长的一个多月,小明已经成长了许多,所以他改了一个名字叫“大明”。
这时他已经不是那个只会做100以内加法的那个“小明”了,现在他甚至会任意长度的正小数的加法。

现在,给你两个正的小数A和B,你的任务是代表大明计算出A+B的值。
 

Input
本题目包含多组测试数据,请处理到文件结束。
每一组测试数据在一行里面包含两个长度不大于400的正小数A和B。
 

Output
请在一行里面输出输出A+B的值,请输出最简形式。详细要求请见Sample Output。
 

Sample Input
 
  
1.1 2.9 1.1111111111 2.3444323343 1 1.1
 

Sample Output
 
  
4 3.4555434454 2.1


大数加法,需要处理多个细节问题,长度不超过400,就算用long long也存不了因此只能用数组来模拟,开一个长度为401的字符型数组(因为还要输入小数点符号),就可以解决输入的问题。对于每个数(a,b)分别再开两个数组分别保存整数部分和小数部分,处理输入的字符串得到整数部分时要注意必须要去掉前导0,有前导0的话会导致后面的加法错误(因此WA了3次T_T),分别做小数和整数的加法,每个数大于等于10的话前一位进1,最后输出同样要注意要去掉后导0

AC代码如下:

#include<iostream>
#include<string>
using namespace std;
char a[401],b[401];
bool search(char a[401]){		//是否有小数点
	int len=strlen(a),i;
	for(i=0;i<len;i++)
		if(a[i]=='.')
			return true;
	if(i>=len)
		return false;
	return false;
}

int main()
{
//	freopen("E:\\in.txt","r",stdin);
//	freopen("E:\\in_test.txt","w",stdout);
	int ca[401],cb[401],tempa[401],tempb[401];
	while(~scanf("%s %s",&a,&b)){		//输入两个数
		int	ib=0,tb=0,cntb=0,i=0,t=0,cnt=0,j,len=0;			//重置计数标志
		int res[401]={0},re[401]={0},ins=0,in=0;
		bool flag=false,flags=true,flagn=false;
		memset(tempa,0,sizeof(tempa));		//重置
		memset(tempb,0,sizeof(tempb));
		memset(ca,0,sizeof(ca));
		memset(cb,0,sizeof(cb));
		if(search(a)){				
			while(a[i]!='.'){
				i++;
				len++;
			}
			for(j=0;a[j]!='.';j++)	//忽略前导0
				if(a[j]!='0') break;
			if(j>=len) tempa[t++]=0;	//如果小数点前面全部是0,则给a整数数组赋值0
			else{
				i=j;			
				while(a[i]!='.'){		//a整数部分
					tempa[t++]=a[i]-'0';
					i++;
				}
			}
			while(a[i++]){			//a小数部分
				ca[cnt]=a[i]-'0';
				cnt++;
			}
			cnt--;
		}
		else{
			while(a[i]){			//无小数点,直接复制到tempa
				tempa[t++]=a[i]-'0';
				i++;
			}
		}
		len=0;				//重置长度以计算b的长度
		if(search(b)){				
			while(b[ib]!='.'){
				len++;
				ib++;
			}
			for(j=0;b[j]!='.';j++)		//忽略前导0
				if(b[j]!='0') break;
			if(j>=len) tempb[tb++]=0;
			else{
				ib=j;
				while(b[ib]!='.'){		//b整数部分
					tempb[tb++]=b[ib]-'0';
					ib++;
				}
			}
			while(b[ib++]){			//b小数部分
				cb[cntb]=b[ib]-'0';
				cntb++;
			}
			cntb--;
		}
		else{	
			while(b[ib]){			//无小数点,直接复制到tempb
				tempb[tb++]=b[ib]-'0';
				ib++;
			}
		}

		if(search(a)||search(b)){	//a或b为小数则进行小数的加法运算			
			int temp=cnt>cntb?cnt:cntb;
			for(i=0;i<temp;i++){
				if(i>=cnt) re[in++]=cb[i];
				else if(i>=cntb) re[in++]=ca[i];
				else re[in++]=ca[i]+cb[i];		//小数部分求和
			}
			for(i=in-1;i>0;i--){		//处理大于10的部分,注意,这里不对re[0]进行处理
				if(re[i]>9){
					re[i]-=10;
					re[i-1]++;
				}
			}
			if(re[0]>9){				//判断第一位小数相加后是否大于10
				re[0]-=10;
				flag=true;
			}
		}

		for(i=t-1,ib=tb-1;i>=0||ib>=0;i--,ib--){		//计算整数部分的和
			if(ib<0) res[ins++]=tempa[i];
			else if(i<0) res[ins++]=tempb[ib];
			else res[ins++]=tempa[i]+tempb[ib];
		}
		if(flag)	res[0]+=1; 
		for(i=0;i<ins-1;i++){			//转化结果中大于10的部分 这里不对res[ins-1]进行处理
			if(res[i]>9){
				res[i]-=10;
				res[i+1]++;
			}
		}
		if(res[ins-1]>9){
			res[ins-1]-=10;
			flagn=true;
		}

		for(i=0;i<in;i++)				//判断小数是否全为0以决定是否输出小数点
			if(re[i]!=0)	break;
		if(i>=in) flags=false;

		if(flagn)cout<<"1";
		for(i=ins-1;i>=0;i--)		//输出整数部分
		cout<<res[i];
		if((search(a)||search(b))&&flags){	//存在小数,且小数部分不全为0
			cout<<".";
			for(i=0;i<in;i++){			//输出小数部分
				for(t=i;t<in;t++)		//忽略小数的后导0
					if(re[t]!=0)break;
				if(t>=in)break;
				cout<<re[i];
			}
		}
		cout<<endl;
	}
	return 0;
}


另外,附上测试用的数据以及输出结果

输入:

1.1 2.9
1.1111111111 2.34443233434
1 1.1
21.3423 2.13423
23432.32 1232
222 232
19.2 12.1
19.2 12.9
2013.2013 3029.3029
99.9 99.9
0.99 99.9
99.9 0.1
99.99 009.11
00098.8 3.32
1.2 1.9
0.1 0.9
1.0 0.10
1.0001 0010.00100

输出:

4
3.45554344544
2.1
23.47653
24664.32
454
31.3
32.1
5042.5042
199.8
100.89
100
109.1
102.12
3.1
1
1.1
11.0011


发布了54 篇原创文章 · 获赞 62 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/u013053268/article/details/47769467