【洛谷】P1601 A+B Problem(高精)
写法一
#include<bits/stdc++.h>
using namespace std;
string stra,strb;
int c[510];
int main(){
//一、读入
cin>>stra>>strb;
//二、补成一样长
while(stra.length()>strb.length()){
strb='0'+strb;
}
while(stra.length()<strb.length()){
stra='0'+stra;
}
//三、计算
int len=stra.length(),jin=0;
for(int i=len-1;i>=0;i--){
c[i]=stra[i]-'0'+strb[i]-'0'+jin;
jin=c[i]/10;
c[i]=c[i]%10;
}
//四、输出 (考虑有多个0的情况)
if(jin){//若加到最后一位产生进位,输出进位
printf("%d",jin);
for(int i=0;i<len;i++) printf("%d",c[i]);
}else{
int flag=0,flag1=0;
for(int i=0;i<len;i++){
if(c[i]==0 && flag1==0){
flag=1;
}else{
flag=0;
flag1=1;
}
if(flag == 0) printf("%d",c[i]);
}
if(flag==1) printf("0");//都是零
}
return 0;
}
```c
在这里插入代码片
思考点:
输入会从在000+0的这种情况,所以存在计算出的c[i]全是0的情况,刚一开始想过用异或做,ans=ans^c[i],if(ans==0) printf(“0”)一部分可以过,但是对于数据123+123会出错,返回2460,因为异或的的中间结果会和操作数相等,导致出现零。
写法二
#include<bits/stdc++.h>
using namespace std;
string a,b,c;
int dw,jin;
int main(){
cin>>a>>b;
//一、读入,把两个数组补成一样长
while(a.length()>b.length()){
b="0"+b;
}
while(a.length()<b.length()){
a="0"+a;
}
//二、相加计算
for(int i=a.length()-1;i>=0;i--){
dw=a[i]-'0'+b[i]-'0'+jin;
jin=dw/10;
dw=dw%10;
c=char(dw+'0')+c;
}
if(jin) c=char(jin+'0')+c;
//三、输出(判断前导0)
int flag=0,flag1=0;
for(int i=0;i<c.length();i++){
if(c[i]=='0' && flag1==0){
flag=1;
}else{
flag=0;
flag1=1;
cout<<c[i];
}
}
if(flag) cout<<"0";
return 0;
}
判断前导零方法:
//三、输出(判断前导0)
int flag=0,flag1=0;
for(int i=0;i<c.length();i++){
if(c[i]=='0' && flag1==0){
flag=1;
}else{
flag=0;
flag1=1;
cout<<c[i];
}
}
if(flag) cout<<"0";
给定一个变量flag,初值为0,假设判断的数字里一开始不存在0,如果遇到0,就把flag置为1;但是会存在第一个是0,后面是其他数字,然后再是0的这种情况(比如001201),但是要不输出的只是第一个非0数字前面的0,一旦遇到其他数字时,就不再判断(其他数字后面的0也要输出),所以设置一个变量flag1,初值为0,代表这个数字只有0,所以if条件判断是两个条件联合,一旦出现不是0的数字,就把flag1置成1,代表这个数字里有其数非0数字,就不需要再判断0了,于是if条件不会再进,在else中输出每个数字。
对于全是0的数字,只需要判断flag是否为1,是1的话,则说明这个数字全是0,所以当把这个数字的全部数位判断完,即在for循环外面,输出1个0即可,表示这个数字是0.
补充新的代码2022-2-4
(1)补充写法1
#include<bits/stdc++.h>
using namespace std;
string s1, s2; //存放输进来的数据
int a[510], b[510], c[510], r;
void duiqi(string s, int len, int s_len, int arr[]) {
for (int i = s_len - 1; i >= 0; i--) {
arr[len - 1] = s[i] - '0';
len--;
}
//数组元素从0对齐改为从最后一个对齐,原先数组长度不够,前面为补0 ,不用把数组翻过来
}
void jiafa(int len) {
for (int i = len - 1; i >= 0; i--) {
int num = a[i] + b[i] + c[i];
c[i] = num % 10;
if (i - 1 < 0) {
r = num / 10;
}else{
c[i - 1] = num / 10;
//整型数组下标出现负数或者大于n-1不一定报错,特判一下
}
}
}
void output(int len, int l1, int l2) {
//最后一位有进位
int i = 0;
if (r != 0) printf("%d", r);//输出进位,再输出后面的数
else {
while(c[i] == 0 && i != len - 1) i++;
//去除前导0,最后一位无论是0还是其他数字都要正常输出
}
//输出第一个不是0的及后面的数,存在只有一个数的情况,可能是0
for (int j = i; j < len; j++)
printf("%d", c[j]);
}
int main() {
cin >> s1 >> s2;
int len, s1_len = s1.length(), s2_len = s2.length();
len = (s1_len >= s2_len)? s1_len : s2_len;
//1.对齐
duiqi(s1, len, s1_len,a);
duiqi(s2, len, s2_len,b);
//2.相加:加数+加数+进位
jiafa(len);
//3.输出,要考虑最后一位有进位的情况,超出了下标0
output(len, s1_len, s2_len);
return 0;
}
```cpp
```c
在这里插入代码片
(2)写法2
#include<bits/stdc++.h>
#define mmax 520
using namespace std;
int a[mmax], b[mmax], c[mmax];
int main() {
string m, n;
cin >> m >> n;
//1.对齐
int len = max(m.length(), n.length());
for (int i = m.length() - 1, j = 1; i >= 0; i--, j++) {
a[j] = m[i] - '0';
}
for (int i = n.length() - 1, j = 1; i >= 0; i--, j++) {
b[j] = n[i] - '0';
}
//2.加法计算
for (int i = 1; i <= len; i++) {
int num = a[i] + b[i] + c[i];
c[i + 1] = num / 10;
c[i] = num % 10;
}
//3.输出处理,考虑最后一位会进位 ,前导0
if (c[len + 1] != 0) {//是否产生进位 ,有进位不用考虑前导0
len++;
}else {
while(c[len] == 0 && len != 1) len--;
//while(!c[len] && len != 1) len--; //也可用这种写法
//前导0,从最后一位开始判断,如果对应的元素是0,长度就相应的减1,因为是倒序输出
}
for (int i = len; i >= 1; i--) {
cout << c[i];
}
//无论如何,都会输出最后一个
return 0;
}
问题记录异常值3221225477:
1、返回异常值3221225477
访问越界,一般是读或写了野指针指向的内存
int i;
if (c[len + 1] != 0) {
i = len + 1;
}
cout<<"i:" << i << endl;
for (int j = i; j >= 1; j--) {
cout << c[i];
}
如果c[len+1]为0的话,也就是没有产生进位,那么i有没有赋初值,所以系统胡乱给了一个值,运行结果可以看出,这个时候再去访问以i为下标的数组元素,内存就会报错,可以让i的初值为len,如果有进位那就i++,然后再输出。这么做有些麻烦,直接让len的值加就可以。写代码的过程中遇到的问题比较有趣,就记录下来。
可以的写法
if (c[len + 1] != 0) {
len++;
}//是否产生进位
for (int i = len; i >= 1; i--) {
cout << c[i];
}