2015年9月29日 星期二

[UVA] 288 - Arithmetic Operations With Large Integers

題意:
大數運算,
運算元只有+ - * 還有**(指數),
輸入測資的運算子都是正數
所以不會有像 -2+2 這樣的測資
但是像 2-2 這樣的測資是可以的喔

還有指數是由後面往前算
所以2**2**3 = 2**(2**3) = 2**8 = 256
0**0=1,
0**0**0 = 0**(0**0) = 0**1 = 0
--------------------------------------------------

我的作法:
我是用C++..好辛苦
首先要先將輸入的柿子做分割,
分割成運算元運算子兩堆
並分別用陣列存取,
例如:
12345678*129876+2**1993
變成
12345678 129876 2 1993

* + **

運算要先從指數開始做,再做乘,最後做加和減
舉個例子:
1**2+3*4+5*6-7**0
運算7**0,(指數要從後面開始做)
然後將運算結果放回式子,1**2+3*4+5*6-1
然後運算1**2,
一樣將運算結果放回式子,1+3*4+5*6-1
指數做完換做乘法,
1+12+5*6-1
1+12+30-1
乘做完最後做加和減
13+30-1
43-1
42

要拿一個運算子和兩個運算元出來做運算,就是從剛剛那兩個陣列去拿,
例如在運算子的陣列裡,[6]="**",
而相對應的運算元的陣列中,[6]和[7]就是 和 0 ,也就是要做運算的兩個運算元!
注意做完運算後要把那兩個運算元和那個運算子刪掉,
並將運算結果再放回運算元陣列!

再來就是自訂大數型別了,
我使用1個大陣列,
最多3000位數,所以可以開750個格子就好,
每個格子存4個位數(10000進位),
例如:數字1234567890,
陣列[0][1][2]分別存[ 7890 ] [ 3456 ] [ 12 ] 。
還有需要一個記號表示該大數的正負。

重載有用到的運算子,
+ ,- ,* ,^(指數) ,<

在處理運算元有幾點需要注意的
不管做哪個運算,最後運算完都需要進位
需要注意正負數
      +:
          A(正)+B(正)直接做A+B,
          A(負)+B(負)直接做A+B,最後結果再作負數記號,
          A(負)+B(正)可以換成B-A
          不會有A(正)+B(負)的情形
      -:
          A-B要先判斷A跟B誰比較大,然後用大的減小的,再看有沒有負號
      *:
          正*正=正,負*負=正,正*負=負,負*正=負
判斷A<B,先判斷正負數後,然後判斷位數,最後再從最高位數開始判斷
輸出時除了最高位數的數字以外,小於1000的都要補0

--------------------------------------------------

/* 20150929
 * hanting
 * UVa 288 - Arithmetic Operations With Large Integers
 * C++
 */
#include <iostream>
#include <vector>
#include <cstdlib> //atoi
#include <cstring> //strtok
#include <iomanip> //setw ,setfill
using namespace std;
#define BNum B.Num
#define Bdigit B.digit
struct BigInteger
{
    bool sign;//1(-),0(+)
    int Num[1001];
    int digit;
    BigInteger(string num="");
    BigInteger operator+(BigInteger &B);
    BigInteger operator-(BigInteger &B);
    BigInteger operator*(BigInteger &B);
    BigInteger operator^(BigInteger &B);
    bool operator<(BigInteger &B);
    bool IsZero();
    void operator--(int);
    void operator*=(BigInteger &B);
    void CountDigit();
    friend ostream& operator<<(ostream& out,BigInteger &B);
};
int main()
{
    string expression,tmp;
    while(cin>>expression)
    {
        copy(expression.begin(),expression.end(),back_inserter(tmp));
        vector<BigInteger> num;
        vector<string> op;
        char *pch=strtok((char*)expression.c_str(),"+-*");
        while(pch)
        {
            num.push_back(BigInteger(pch));
            pch=strtok(NULL,"+-*");
        }
        expression=tmp;

        pch=strtok((char*)expression.c_str(),"0123456789");
        while(pch)
        {
            op.push_back(pch);
            pch=strtok(NULL,"0123456789");
        }
        for(int i=op.size()-1;i>=0;i--)
        {
            if(op[i]=="**")
            {
                num[i]=num[i]^num[i+1];
                op.erase(op.begin()+i);
                num.erase(num.begin()+i+1);
            }
        }
        for(int i=0;i<op.size();i++)
        {
            if(op[i]=="*")
            {
                num[i]=num[i]*num[i+1];
                num.erase(num.begin()+i+1);
                op.erase(op.begin()+i);
                i--;
            }
        }
        for(int i=0;i<op.size();i++)
        {
            if(op[i]=="+") num[i]=num[i]+num[i+1];
            else if(op[i]=="-")num[i]=num[i]-num[i+1];
            num.erase(num.begin()+i+1);
            op.erase(op.begin()+i);
            i--;
        }
        cout<<num[0]<<endl;
        tmp.clear();
    }
    return 0;
}
BigInteger::BigInteger(string str):sign(0),digit(0),Num{0}
{
    while(str.size()>4)
    {
        string tmp=str.substr(str.size()-4);
        Num[digit++]=atoi(tmp.c_str());
        str.erase(str.size()-4,4);
    }
    if(str.size())
    {
        Num[digit++]=atoi(str.c_str());
    }
}
void BigInteger::CountDigit()
{
    for(int i=1000;i>=0;i--)
    {
        if(Num[i]!=0)
        {
            digit=i+1;
            return ;
        }
    }
}

void BigInteger::operator--(int)
{
    if(digit<=0) return ;
    Num[digit-1]--;
    for(int i=0;i<digit-1;i++)
    {
        Num[i]+=9999;
    }
    CountDigit();
    for(int i=1;i<digit;i++)
    {
        Num[i]+=Num[i-1]/10000;
        Num[i-1]%=10000;
    }
    CountDigit();
}
void BigInteger::operator*=(BigInteger &B)
{
    *this=(*this)*B;
}
bool BigInteger::IsZero()
{
    return digit==1 and Num[0]==0;
}
bool BigInteger::operator<(BigInteger &B)
{
    if(sign==B.sign)
    {
        if(sign==0)//都是正數
        {
            if(digit<Bdigit) return true;
            else if(digit==Bdigit)
            {
                for(int i=digit-1;i>=0;i--)
                {
                    if(Num[i]<BNum[i]) return true;
                    else if(Num[i]==BNum[i]) continue;
                    else return false;
                }
            }
            else return false;
        }
        else//都是負數
        {
            if(digit<Bdigit) return false;
            else if(digit==Bdigit)
            {
                for(int i=digit-1;i>=0;i--)
                {
                    if(Num[i]<BNum[i]) return false;
                    else if(Num[i]==BNum[i]) continue;
                    else return true;
                }
            }
            else return true;
        }
    }
    else if(sign==1 and B.sign==0)//負數<正數
    {
        return true;
    }
    else//正數<負數
    {
        return false;
    }
}
BigInteger BigInteger::operator+(BigInteger &B)
{
    BigInteger result;
    if(sign==B.sign)
    {
        for(int i=0;i<digit or i<Bdigit;i++)
        {
            result.Num[i]+=Num[i]+BNum[i];
            result.Num[i+1]+=result.Num[i]/10000;
            result.Num[i]%=10000;
        }
    }
    else//-3+2
    {
        this->sign=0;
        result=B-(*this);
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator-(BigInteger &B)
{
    BigInteger result;
    if(*this<B)
    {
        result.sign=1;//負數
        if(Bdigit>1)
        {
            BNum[Bdigit-1]--;
            for(int i=Bdigit-2;i>0;i--)
            {
                BNum[i]+=9999;
            }
            BNum[0]+=10000;
            for(int i=0;i<Bdigit;i++)
            {
                if(sign==0) result.Num[i]=BNum[i]-Num[i];
                else result.Num[i]=BNum[i]+Num[i];
            }
        }
        else
        {
            if(sign==0)result.Num[0]=BNum[0]-Num[0];
            else result.Num[0]=BNum[0]+Num[0];
        }
    }
    else
    {
        if(digit>1)
        {
            Num[digit-1]--;
            for(int i=digit-2;i>0;i--)
            {
                Num[i]+=9999;
            }
            Num[0]+=10000;
            for(int i=0;i<digit;i++)
            {
                result.Num[i]=Num[i]-BNum[i];
            }
        }
        else
        {
            result.Num[0]=Num[0]-BNum[0];
        }
    }
    for(int i=1;i<Bdigit or i<digit;i++)
    {
        result.Num[i]+=result.Num[i-1]/10000;
        result.Num[i-1]%=10000;
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator*(BigInteger &B)
{
    BigInteger result;
    if(sign) result.sign=!result.sign;
    if(B.sign) result.sign=!result.sign;
    for(int i=0;i<digit;i++)
    {
        for(int j=0;j<Bdigit;j++)
        {
            result.Num[i+j]+=Num[i]*BNum[j];
        }
    }
    for(int i=1;i<digit+Bdigit;i++)
    {
        result.Num[i]+=result.Num[i-1]/10000;
        result.Num[i-1]%=10000;
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator^(BigInteger &B)
{
    BigInteger result("1");
    while(!B.IsZero())
    {
        result*=(*this);
        B--;

    }
    return result;
}

ostream& operator<<(ostream& out,BigInteger &B)
{
    if(Bdigit==0) out<<0;
    else
    {
        if(B.sign) cout<<"-";
        if(Bdigit) cout<<BNum[Bdigit-1];
        for(int i=Bdigit-2;i>=0;i--)
        {
            out<<setw(4)<<setfill('0')<<BNum[i];
        }
    }
    return out;
}

沒有留言:

張貼留言