POJ 2116解題報告

Death to Binary?
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 1494   Accepted: 461

Description

The group of Absurd Calculation Maniacs has discovered a great new way how to count. Instead of using the ordinary decadic numbers, they use Fibonacci base numbers. Numbers in this base are expressed as sequences of zeros and ones similarly to the binary numbers, but the weights of bits (fits?) in the representation are not powers of two, but the elements of the Fibonacci progression (1, 2, 3, 5, 8,... - the progression is defined by F0 = 1, F1 = 2 and the recursive relation Fn = Fn-1 + Fn-2 for n >= 2). 

For example 1101001Fib = F0 + F3 + F5 + F6 = 1 + 5 + 13 + 21 = 40. 

You may observe that every integer can be expressed in this base, but not necessarily in a unique way - for example 40 can be also expressed as 10001001Fib. However, for any integer there is a unique representation that does not contain two adjacent digits 1 - we call this representation canonical. For example 10001001Fib is a canonical Fibonacci representation of 40. 

To prove that this representation of numbers is superior to the others, ACM have decided to create a computer that will compute in Fibonacci base. Your task is to create a program that takes two numbers in Fibonacci base (not necessarily in the canonical representation) and adds them together. 

Input

The input consists of several instances, each of them consisting of a single line. Each line of the input contains two numbers X and Y in Fibonacci base separated by a single space. Each of the numbers has at most 40 digits. The end of input is not marked in any special way.

Output

The output for each instance should be formated as follows: 

The first line contains the number X in the canonical representation, possibly padded from left by spaces. The second line starts with a plus sign followed by the number Y in the canonical representation, possibly padded from left by spaces. The third line starts by two spaces followed by a string of minus signs of the same length as the result of the addition. The fourth line starts by two spaces immediately followed by the canonical representation of X + Y. Both X and Y are padded from left by spaces so that the least significant digits of X, Y and X + Y are in the same column of the output. The output for each instance is followed by an empty line. 

Sample Input

11101 1101
1 1

Sample Output

   100101
+   10001
  -------
  1001000

   1
+  1
  --
  10

Source

        

        這道題是一道比較有趣的題,可以利用斐波那契數列的一些性質來求解。有些人的做法是先將輸入的兩串數列化爲兩個十進制數字,再計算其和,得到三個十進制數字,對於每個十進制數字,按照公式:F[N]<=NUM<F[N+1](F[N]表示第N個斐波那契數);NUM-=F[N];進行迭代,直到NUM==0爲止。這些需要計算斐波那契數列的值。代碼寫起來也比較短。

    當然,不這樣做也行。我們可以從式子的相加以及變換中找到一些規律,第一個規律就是F(1)=2*F(0),即從右向左,第二位(對應F(1))的數是第一位(對應F(0))數的2倍。這顯而易見,F(1)=2,F(0)=1。其次就是最常見的式子,F(k+2)=F(k+1)+F(k),這個式子可以將相鄰的兩個1變爲0,將1的值進位到更高的位。還有一個式子2*F(k+2)=2*F(k+1)+2*F(k)=F(k+1)+F(k)+F(k+1)+F(k)=F(k+2)+F(k+1)+F(k)=F(k+3)+F(k),我們就可以得到2*F(k+2)=F(k+3)+F(k),當然,進行變換以後就可以寫成2*F(k)=F(k+1)+F(k-2)(k>=2),因爲F(2)=3,F(1)=2,F(0)=1,則F(1)=F(2)+F(0)不滿足上式。

   這樣我們只要這幾個有用的遞推關係式就可以對數字進行處理從而得出答案。在對數字進行處理時,需要先從高位向低位處理一遍,將相鄰的1拆開,但是單純進行一次遍歷還可能導致出現相鄰的1,比如,101011,從高位向低位處理以後仍然存在相鄰的1,所以還需要再從低位向高位再處理一遍。這樣才能保證不存在相鄰的1。對三個數按照同樣方法處理即可。當然,還需要注意除去前導0。類似於大數加法,還需要考慮在除去前導0時,如果這個數本來就爲0的情況。因此要注意兩個加數中有1個0,兩個0的情況。考慮這種特殊數據。

   方法1參考代碼 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

char a[50],b[50],c[50];
int f[50];
char fa[50],fb[50],fc[50];
void solve(char a[],int sum)
{
    while(sum>0)
    {
        int t=lower_bound(f,f+45,sum)-f,ans=f[t];
        if(ans>sum) a[t-1]=1,sum-=f[t-1];
        else a[t]=1,sum-=f[t];
    }
}

void print(char a[],int t,int ka,int km)
{
    int k=45;
    if(t==2) printf("+ ");
    else
    {
        printf("  ");
        if(t==3)
        {
            REP(i,0,km)
              printf("-");
            printf("\n");
            return;
        }
    }
    if(ka>=0)
    {
        rep(i,0,km-ka)
           printf(" ");
        RREP(i,ka,0)
           printf("%d",a[i]);
        printf("\n");
    }
    else
    {
        rep(i,0,km)
           printf(" ");
        printf("0\n");
    }
    if(t==4)
        printf("\n");
}

int main()
{
    f[0]=1,f[1]=2;
    rep(i,2,45)
       f[i]=f[i-1]+f[i-2];
    while(~scanf("%s%s",a,b))
    {
        int k1=strlen(a),k2=strlen(b);
        int sum1=0,sum2=0,sum=0;
        CLR(fa);CLR(fb);CLR(fc);
        rep(i,0,k1)
           if(a[i]=='1')
               sum1+=f[k1-1-i];
        rep(i,0,k2)
           if(b[i]=='1')
               sum2+=f[k2-1-i];
        sum=sum1+sum2;
        solve(fa,sum1);solve(fb,sum2);solve(fc,sum);
        int ka=45,kb=45,kc=45,k=0;
        while(ka>=0&&fa[ka]==0) ka--;
        while(kb>=0&&fb[kb]==0) kb--;
        while(kc>=0&&fc[kc]==0) kc--;
        k=max(k,ka);k=max(k,kb);k=max(k,kc);
        print(fa,1,ka,k);print(fb,2,kb,k);print(fb,3,kb,k);print(fc,4,kc,k);
    }
}

       方法二參考代碼

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

char str1[50],str2[50];
char a[50],b[50],c[50];
int solve(char a[])
{
    int k=50;
    while(k>=0&&a[k]==0) k--;
    while(k>=0)
    {
        if(a[k]>=1)
        {
            while(k-1>=0&&(a[k-1]>=1&&a[k]>=1))
            {
                a[k+1]++,a[k]--,a[k-1]--;
                if(a[k]==0)
                {
                    k--;
                    break;
                }
                else if(a[k-1]==0)
                {
                    k-=2;
                    break;
                }
            }
            if(k-1>=0&&a[k-1]==0)
            {
                while(a[k]>=2)
                {
                    if(k>1)
                        a[k]-=2,a[k+1]++,a[k-2]++;
                    else if(k==1)
                        a[k]-=2,a[k+1]++,a[k-1]++;
                    else
                    {
                        k--;
                        break;
                    }
                }
                k--;
            }
            else if(k>=0) k--;
        }
        else k--;
    }
    k=0;
    while(k<50&&a[k]==0) k++;
    if(k==0)
    {
        while(a[0]>=2)
        {
            a[1]++;
            a[0]-=2;
        }
    }
    while(k<50)
    {
        if(a[k]>=1)
        {
            while(k+1<50&&(a[k+1]>=1&&a[k]>=1))
            {
                a[k+2]++,a[k]--,a[k+1]--;
                if(a[k]==0)
                {
                    k++;
                    break;
                }
                else if(a[k+1]==0)
                {
                    k+=2;
                    break;
                }
            }
            if(k+1<=50&&a[k+1]==0)
            {
                while(a[k]>=2)
                {
                    if(k>1)
                        a[k]-=2,a[k+1]++,a[k-2]++;
                    else if(k==1)
                        a[k]-=2,a[k+1]++,a[k-1]++;
                    else
                    {
                        k++;
                        break;
                    }
                }
                k++;
            }
            else if(k+1>50) k++;
        }
        else k++;
    }
    k=50;
    while(k>=0&&a[k]==0) k--;
    return k;
}

void print(int ka,int shu,int num)
{
    if(num==1) printf("  ");
    if(num==2) printf("+ ");
    if(ka>=0)
    {
        for(int i=0; i<shu-ka; i++)
            printf(" ");
        for(int i=ka; i>=0; i--)
        {
            if(num==1)
                printf("%d",a[i]);
            else if(num==2)
                printf("%d",b[i]);
        }
    }
    else
    {
        for(int i=0; i<shu; i++)
            printf(" ");
        printf("0");
    }
    printf("\n");
}

void print1(int k,int shu)
{
    printf("  ");
    if(shu>=0)
    {
        for(int i=shu; i>=0; i--)
        {
            if(k==1) printf("-");
            else printf("%d",c[i]);
        }
    }
    else
    {
        if(k==1) printf("-");
        else printf("0");
    }
    printf("\n");
    if(k==2) printf("\n");
}

int main()
{
    while(~scanf("%s%s",str1,str2))
    {
        CLR(a);CLR(b);CLR(c);
        int k1=strlen(str1),k2=strlen(str2);
        for(int i=0; i<k1; i++)
            a[i]=str1[k1-1-i]-'0';
        for(int i=0; i<k2; i++)
            b[i]=str2[k2-1-i]-'0';
        int ka=solve(a);
        int kb=solve(b);
        for(int i=50; i>=0; i--)
            c[i]=a[i]+b[i];
        int kc=solve(c);
        int shu=max(max(ka,kb),kc);
        print(ka,shu,1);print(kb,shu,2);print1(1,shu);print1(2,shu);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章