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 F n = F n-1 + F n-2 for n >= 2). 

For example 1101001 Fib = 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 10001001 Fib. However, for any integer there is a unique representation that does not contain two adjacent digits 1 - we call this representation canonical. For example 10001001 Fib 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);
    }
}

POJ1753题目为"Flip Game",题目给出了一个4x4的棋盘,每个格子有黑色或白色,每次翻转一个格子会同时翻转它上下左右四个格子的颜色,目标是把整个棋盘都变为同一种颜色,求把棋盘变成同种颜色的最小步数。 解题思路: 一般关于棋盘变色的题目,可以考虑使用搜索来解决。对于POJ1753题目,可以使用广度优先搜索(BFS)来解决。 首先,对于每个格子,定义一个状态,0表示当前格子是白色,1表示当前格子是黑色。 然后,我们可以把棋盘抽象成一个长度为16的二进制数,将所有格子的状态按照从左往右,从上往下的顺序排列,就可以用一个16位的二进制数表示整个棋盘的状态。例如,一个棋盘状态为: 0101 1010 0101 1010 则按照从左往右,从上往下的顺序把所有格子的状态连接起来,即可得到该棋盘的状态为"0101101001011010"。 接着,我们可以使用队列来实现广度优先搜索。首先将初始状态加入队列中,然后对于队列中的每一个状态,我们都尝试将棋盘上的每个格子翻转一次,生成一个新状态,将新状态加入队列中。对于每一个新状态,我们也需要记录它是从哪个状态翻转得到的,以便在得到最终状态时能够输出路径。 在搜索过程中,我们需要维护每个状态离初始状态的步数,即将该状态转换为最终状态需要的最小步数。如果我们找到了最终状态,就可以输出答案,即最小步数。 代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值