给定-100到100的两个数n,m,每次只能对n加1,减1,乘2,求n变为m的最小步数

题目:给定-100到100的两个数n,m,每次只能对n减1,加1,乘2,求n变为m的最小步数
例子:

n=3,m=11,需要3步从n变为m,先乘2,再乘2,再减一

n=3,m=5,需要2步,先加1,再加1

思路:广度优先+分支限界
因为有3种操作,先遍历n经过3次操作后的结果,如果结果中含有m,就只需要1步,否则就对3次操作后的结果重复此操作,再遍历过程中用一个标记数组记录已经处理过的数,后面再遇到就不再处理,减少了操作次数。

                                        3
                              /         |           \
                            2           4            6
                         /  |  \      /  |  \       /  |  \
                        1   3*  4*    3*  5  8     5*  7  12

从上面我们可以看出3变为5只需要2步,就是需要遍历2层,所以用层序遍历即可。因为我们是一层一层遍历的,所以最先找到的就是最小的。

#include<iostream>
#include<queue>
using namespace std;
int flag[1000];
int step = 0;
void find(int n,int m) {
	queue<int> que;	
	que.push(n-1);	
	que.push(n+1);
	que.push(n*2);
	while (!que.empty()) {	
		int n = que.size();
		for (int i = 0; i < n;i++) {
			int val = que.front();
			que.pop();
			if (flag[val] == 1) continue;   //分支限界:如果已经处理过则不再处理
			if (val == m) {
				step++;
				return;
			}
			que.push(val- 1);
			que.push(val + 1);
			que.push(val * 2);
			flag[val] = 1;
		}
		step++;
	}
}
int main() {
	int n, m;
	while (cin>>n>>m) {
		step = 0;
		memset(flag, 0, sizeof(flag));
		flag[n] = 1;
		if (n > 0 && m > 0) {
			find(n, m);
			cout << step<<endl;
		}
		else if (n > 0 && m < 0) {
			find(n, m);
			cout << step << endl;
		}
		else if (n < 0 && m > 0) {
			find(n, m);
			cout << step << endl;
		}
		else {
			find(0-n, 0-m);
			cout << step << endl;
		}	
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章