hdoj1104,Remainder

1.原来很简单,就是广搜。

2.怎么像迷宫一样,把几个选项转换成方向是一个问题。这里实在for里面加了四个判断。不能像迷宫那样,直接用两行就好了。

3.怎么确定bfs的停止条件。后来想到了,就是余数。如果把余数压进谋个容器,通过去除重复,则队列里的数就会保持一定值并在最后逐渐减少。不会陷入无限循环。但是我没有成功。用了队列和数组,向量,都没有成功。后来参考别人写的,才觉得用一个布尔数组是一个好方法。不要在struct里加入所有的东西。有时分开也是一个好的选项。不是只有整合才好。

4.还有一个问题,就是为什么每次取与之后还加上一个,为了防止负数的出现。
5,还有,为什么km,因为((n oper m)%k oper m)%k 是不是等于(n oper m oper m)%k
  对于op运算是成立的,但是%参与时,结果是不等。例如:
   记n = 2, m = 8, k =3.
   则((n * m)%k % m)%k = 1
   而(n * m % m)%k = 0。
   其实km就是把范围扩大了,以为取鱼的时候,km很大,范围更大了。保证而这一样。至于为什么保持而这一样,
   就是上面的例子。有时候是相当于连续预算m的,那样就会出现那种情况了。
6,还有一个有趣的结论,摘自hdoj的讨论。
%只能出现在第一个位置或者出现在*的后面,且%最多只能出现两次。
   因为对任意n,( n pe m ) % m = n % m. 对于乘法则是不一定的,n * m % m 必为0。
 由于一系列{+,-,%}运算相当于在n的基础上,‘+’相当于加上若干个m,‘-’相当于减去若干
个m,‘%’相当于一次同时减去(或者加上)若干个m。而他们的总和带来的结果就是n的变化是
m的整数倍,所以上面的式子相等。也就是说如果有一个序列中有‘%’,则它的前面要么是空的,
要么是‘*’,因为如果是其他的只会使得操作序列更长。例如:
    +-+-+++%+*+-*-*可以变成%+*+-*-*,后者比前者更短。
    *%+-+-***-+*%+*这样的路径也是不存在的,因为*%使得n为0,而后面的*%也为0,
    重复,所以不会入队列的。
因为‘%’出现的情况很有限,并且出现的位置,也可以知道。特殊处理一下,就可以了。其他的
对k取余没有问题。

#include<iostream>
#include<queue>
#include<string>
using namespace std;

int n,m,k;
struct Node
{
	int v;
	int t;
	string s;
};
const int maxn = 1000000+10;
int map[maxn];
int km;
void bfs();
int main()
{

	while(cin>>n>>k>>m&&!(n==0&&m==0&&k==0))
	{
		km = k*m;
	   bfs();
	}
	return 0;
}

void bfs()
{
	memset(map,0,sizeof(map));
	queue<Node> q;
	Node node;
	node.v = n;
	node.s = "";
	node.t = 0;
	map[(n%k+k)%k]=1;
	q.push(node);
	Node nextNode;
	while(!q.empty())
	{
		node = q.front();
		q.pop();
		if((node.v%k+k)%k==((n+1)%k+k)%k)
		{
			cout << node.t<<endl;
			cout <<node.s<<endl;
			return ;
		}
		nextNode.t = node.t+1;
		for ( int i = 0; i < 4; i++ )
		{
			if(i ==0)
			{
				nextNode.v = (node.v+m)%km;
				nextNode.s = node.s+"+";
			}
			else if(i==1)
			{
				nextNode.v = (node.v-m)%km;
				nextNode.s = node.s+"-";
			}
			else if(i==2)
			{
				nextNode.v = (node.v*m)%km;
				nextNode.s = node.s+"*";
			}
			else
			{
				nextNode.v = (node.v%m+m)%m%km;
				nextNode.s = node.s+"%";
			}
			
			if(map[(nextNode.v%k+k)%k]==0)
			{
				q.push(nextNode);
				//下面等号写成两个,导致内存超。用了一个小时才找到
				map[(nextNode.v%k+k)%k]=1;
			}
		}
	}
	cout << 0<<endl;
	return;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值