[NBOJ0031][Nim-B* Sum]

[题目要求]

http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=31

[题目涉及的相关理论与算法]
1,博弈论中的NIM游戏。虽然题目中求的Nim和是Nim游戏中的策略,但是和游戏本身关系不大,相当于实现游戏中一个算法。开始不理解的时候觉得很深奥,但是看过一些介绍之后有了初步的了解就好多了。
推荐一个介绍:http://blog.csdn.net/qiankun1993/article/details/6765688,这里面比较详细了介绍了Nim游戏。
2,进制转换的相关运算,这个应该属于基本功。
3,理解“异或运算”实质是在二进制下的不进位加法。本题中出现的运算针对的是B进制下。

[题目中需要注意的地方]
觉得有两点值得一说吧,一个是两个B进制下的数进行运算时要注意对准位。数组存的是逆序的结果。就是a[0]存的是最低位的。
还有一个是,额。。在最后算回十进制数时,我的算法是在循环内多乘了一个B,结果要除以B,但是就是这一个多乘,造成提交时的结果溢出了。。到最后慢慢比较后才发现。。所以千万留神,将结果改成用long long型就AC了。最好的解决办法就是改一下循环体的构造,不多乘那一下。。。这也说明系统测试时的数据真的很大。。都是边缘啊= =。

[思路过程]
开始没太看明白,后来看过介绍之后,对这个博弈论中的经典问题有了了解。知道了Nim和的定义和求法。后面就比较好办了。顺序就是先将两个数转换为相应的进制,然后按位进行不进位加法。得到的结果再转换为十进制输出。

[代码]

#include<iostream>
using namespace std;
int const L = 21;	//因为位数最多的情况就是2进制,而2000000对应的2进制不超过21位。所以设L为21.
void casesolve()
{
	int result[L];
	int X[L];
	int Y[L];
	int n,b,x,y;
	memset(X,0,sizeof(X));
	memset(Y,0,sizeof(Y));
	memset(result,0,sizeof(result));
	cin>>n>>b>>x>>y;
	int i=0;	//辅助的参数。
	int max=0;	//使用max来记录两个转换后的进制数最高的位数,当然这里说的“位数”是B进制下的分组数。
	while(x != 0)	//将x转换为b进制。
	{
		X[i++] = x % b;
		x = x/b;
	}
	max = i;	//此时max记录下x的最高位。
	i=0;	
	while(y != 0)	//同理处理y
	{
		Y[i++] = y % b;
		y = y/b ;
	}
	if(i > max) max =i;//比较x和y哪一个位数高。
	i=0;
	while(i != max)		//这一步是将两个B进制下进行不进位加法。用到了max。
	{
		result[i] = (X[i] + Y[i]) % b;
		i++;
	}
	int sum = 0;
	i=max;
	while((i--) >= 1 )
	{
		sum = sum * b;			//注意这两步骤的顺序。这里是对进制转换的基本算法。
		sum = sum+result[i];	
	}
	cout<<n<<" "<<sum<<endl;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);	
	int t;
	cin>>t;
	while((t--) > 0)
	{
		casesolve();
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}

[尾声]
做这道题的时候顺便了解了一点点博弈论中的知识,觉得奥妙无穷啊。今天总算遇到的都是不太讨厌的题目! 还不错~

 

你可能感兴趣的:(ACM,进制转换,博弈论,Nim游戏,Nim-B*Sum)