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))同解。

原文地址:https://www.cnblogs.com/Ivy-End/p/4319748.html