zoukankan      html  css  js  c++  java
  • SGU[126] Boxes

    Description

    描述

    There are two boxes. There are A balls in the first box, and B balls in the second box (0 < A + B < 2147483648). It is possible to move balls from one box to another. From one box into another one should move as many balls as the other box already contains. You have to determine, whether it is possible to move all balls into one box.

    有两个盒子。第一个盒子里有A个球,第二个盒子里有B个球(0 < A + B < 2147483648)。可以将球从一个盒子中移动到另一个盒子中。移动时需要满足移动到目标盒子中的球与其中原有的球的个数相等。你需要判断是否能够将所有的球都移动到一个盒子中。

     

    Input

    输入

    The first line contains two integers A and B, delimited by space.

    第一行包含两个整数A和B,以空格分隔。


    Output

    输出

    First line should contain the number N - the number of moves which are required to move all balls into one box, or -1 if it is impossible.

    第一行包含一个数字N——将所有球移动到一个盒子中所需要的步数,如果不可能则为-1。


    Sample Input

    样例输入

    2 6


    Sample Output

    样例输出

    2

     

    Analysis

    分析

    第一个方法是模拟,就是设定一个规定步数(经过反复测试,在给定的数据范围内32步即可满足要求),如果在规定步数内完成任务,则输出步数,否则输出-1。

     

    第二个方法是数学:

    首先我们有一个结论(x, y)与(x / gcd(x, y), y / gcd(x, y))具有相同的答案。

    证明:我们可以运用整体的思想,将gcd(x, y)个球看成一个球。例如5 5,我们可以看成1 1,其中后面的1代表了5个小球。

    有了上面的结论,我们只需要处理(X, Y)即可,其中X = x / gcd(x, y), Y = y / gcd(x, y)。

    很明显,当X + Y为奇数时无解,因为要完成任务,必定有状态(A, A)出现,其中A = (X + Y) / 2。

    接下来,我们来推到一般解的情况,令N = X + Y,并设K步完成任务:

    步骤数目 解空间状态
    K (N, 0)
    K-1 (N / 2, N / 2)
    K-2 (N / 4, 3N / 4)
    K-3 (N / 8, 7N / 8)、(5N / 8, 3N / 8)
    K-4 (N / 16, 15N / 16)、(9N / 16, 7N / 16)、(5N / 16, 11N / 16)、(13N / 16, 3N / 16)
    …… ……

    我们可以看到,当N为2的幂次时有解,其中2的指数则为所需要的步骤数(这也就验证了模拟时只需要32步即可),这样我们就可以很轻松的解决这个问题了。

     

    Solution

    解决方案

    模拟:

    #include <iostream>
    
    using namespace std;
    
    const int MAX = 32;
    
    int main()
    {
    	int x, y;
    	while(cin >> x >> y)
    	{
    		int nCnt = 0;
    		while(x != 0 && y != 0 && nCnt <= MAX)
    		{
    			if(x <= y) { y -= x; x += x; }
    			else { x -= y; y += y; }
    			nCnt++;
    		}
    		if(x != 0 && y != 0) { cout << -1 << endl; }
    		else { cout << nCnt << endl; }
    	}
    	return 0;
    }

    数学:

    #include <iostream>
    
    using namespace std;
    
    int gcd(int x, int y);
    
    int main()
    {
    	int x, y;
    	while(cin >> x >> y)
    	{
    		int nCnt = 0;
    		int nTmp = gcd(x, y);
    		x /= nTmp; y /= nTmp;
    		int nSum = x + y;
    		while(nSum > 1)
    		{
    			if(nSum & 1) { nCnt = -1; break; }
    			else { nCnt++; nSum >>= 1; }
    		}
    		if(x == 0 || y == 0) { nCnt = 0; }
    		cout << nCnt << endl;
    	}
    }
    
    int gcd(int x, int y)
    {
    	if(y == 0) { return x; }
    	else { return gcd(y, x % y); }
    }
    

      

    这道数学题想了好久,终于AC了,主要在于一个逆推的过程以及看出(x, y)与(x / gcd(x, y), y / gcd(x, y))同解。

  • 相关阅读:
    《将博客搬至CSDN》
    关于数据分析师出路的思考
    什么样的人适合学金融工程?
    再谈到计算机网络的学习
    学习金融工程的随笔
    走上量化投资道路的回顾
    idea构建docker镜像并发布到服务器
    Elastic:菜鸟上手指南
    分布式事务专题
    mysql 慢查询日志分析与使用
  • 原文地址:https://www.cnblogs.com/Ivy-End/p/4319748.html
Copyright © 2011-2022 走看看