2014年3月13日木曜日

AOJ 0015 c

AOJの0015、入力された2つの数の和を出す問題なのですが、条件として80桁まで計算できないといけないみたいです。

問題文→http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0015



long long unsigned int型(64ビット符号無し整数)でも0~18,446,744,073,709,551,615で20桁までしか扱えません。
そこで文字列として入力された数字を配列にひとつずつ入れていき、あとは筆算の要領で同じ桁同士足していけばいいと思ったのですが、何故かおかしな値が出てきてしまい何故だろうと悩みました。


いろいろ調べてみた結果、ここで初めて文字列には全て番号が割り振られていて、それは数字であっても同様であるということを知りました。
例えば'0'は48が割り当てられていているので、整数値の文字列をその通りの数字として扱うには

(整数値の文字列)- '0'
(整数値の文字列)- 48

のどちらかをする必要があるというわけです。

また、その他の方法として、整数値の文字列を整数型( int型 )に型変換するatoi()というものもあります。
参考→http://simd.jugem.jp/?eid=85

以下に自分の書いたコードを載せますが、実はこれ「time limit exceeded」でまだ通過していません。
足し算は成功しているのですが、時間がかかるようで…。
近いうちに他の言語で再挑戦しようと思っています。
#include <stdio.h>
#include <string.h>

int main(void)
{
    unsigned char num1[100],num2[100];
    int ia,ib,i,j,k,l,num,ex,large,small;
    int size1,size2;
    int sum[100];

    scanf("%d",&num);//データセット数

    for (l = 0; l < num; ++l)
    {
        scanf("%s",num1);
        scanf("%s",num2);

        size1 = strlen(num1);
        size2 = strlen(num2);

        if (size2 >= size1)// 「>」にすると同じ値の時困る
        {
            large = (size2 - 1);
            small = (size1 - 1);
        }
        else if (size1 >= size2)
        {
            large = (size1 - 1);
            small = (size2 - 1);
        }

        //80桁以上でoverflow
        if (large > 80)
        {
            printf("overflow\n");
            continue;
        }


        //num1の数字の並びを逆に******************************************
        for(ia = 0; ia < 100; ia++)
        {
            if(num1[ia+1] == '\0')break;   //NULL文字は交換しないように
            
            ex = num1[ia];
            num1[ia] = num1[ia+1];
            num1[ia+1] = ex;
        }

        for (j = ia; j > 0 ; --j) //iaは文字列の大きさになってる
        {
            for (k = 0; k < j-1; ++k) //先頭の文字を後ろへ送ってる
                                      //ただしひとつずつ短く 一歩手前まで
            {
                ex = num1[k];
                num1[k] = num1[k+1];
                num1[k+1] = ex;
            }
        }

        j=0;
        k=0;

        //num2の数字の並びを逆に******************************************
        for(ib = 0; ib < 100; ib++)
        {
            if(num2[ib+1] == '\0')break;   //NULL文字は交換しないように
            
            ex = num2[ib];
            num2[ib] = num2[ib+1];
            num2[ib+1] = ex;
        }

        for (j = ib; j > 0 ; --j) //ibは文字列の大きさになってる
        {
            for (k = 0; k < j-1; ++k) //先頭の文字を後ろへ送ってる
                                      //ただしひとつずつ短く 一歩手前まで
            {
                ex = num2[k];
                num2[k] = num2[k+1];
                num2[k+1] = ex;
            }
        }

        j=0;
        k=0;


        //共に1桁の値が入力された時
        //(largeに0が入るから表示されない不具合回避)
        if (ia == 0 && ib == 0)
        {
            printf("%d\n", (num1[0]-48) + (num2[0]-48));
            continue;
        }

        //異なる桁が入力された時
        //以降の足し算の処理のためずれの分だけ0を格納
        if (ia != ib)
        {
            for (j = small + 1; j <= large ; ++j)
            {
                if (ia < ib)
                {
                    num1[j] = '0';
                }
                else if (ib < ia)
                {
                    num2[j] = '0';
                }
            }
        }

        //初期化
        for (i = 0; i <= large+1; ++i)
        {
            sum[i] = 0;
        }

        i = 0;

        for (i = 0; i <= large; ++i)
        {
            sum[i] += ((num1[i]-'0') + (num2[i]-'0'));

            if (sum[i] >= 10)//筆算的なアレで10超えてたら
            {
                sum[i] -= 10;   //1の位の数字を入れる
                sum[i+1] += 1;; //繰り上げ

                //(例)80 + 50の時など桁が変わる場合の処理
                if (i == large)
                {
                    large += 1;
                    break;
                }
            }
        }

        //足し算結果が80桁越えてもoverflow
        if (large > 80)
        {
            printf("overflow\n");
            continue;
        }

        for (i = large; i >= 0; --i)
        {
            printf("%d", sum[i]);
        }
        printf("\n");

        i = 0;

    }

    return 0;
}

0 件のコメント:

コメントを投稿