暴力搜尋演算法的典型應用——24點遊戲

凜冬烈焰發表於2018-05-24

“24點”是個棋牌類益智遊戲,要求四個數字運算結果等於二十四。這種型別的題目可以通過編寫程式讓計算機完成。一個更具有普遍性的題目如下:

每次給若干個數和一個目標數,讓你判斷,利用這些數能否通過簡單的運算(加,減,乘,除)得到那個目標數。如果能則輸出目標數,否則輸出這幾個數能湊到的小於目標數的最大的那個數。備註:要求每個數都要用到,並且除法必須要求能夠進行整除,否則就不能進行除法;例如,4/2可以,1/7和9/4就不可以。

例1:

輸入五個數為:1 2 3 7 100;目標數為:573

輸出:573 (因為:(((100-1)*2)-7)*3 = 573)

 

例2:

輸入五個數為:67 69 58 22 2;目標數為:929

輸出:923 (因為:(22-(67-58))*(69+2)=923)


例3:

輸入四個數為:1 3 7 13;目標數為:30

輸出:30(因為:((7*13)-1)/3=30)


用暴力搜尋演算法列舉所有可能性即可解決此問題。在這裡我介紹一下我的解決思路:首先用一個動態陣列(在C++中,推薦用STL標準庫中的vector來實現動態陣列)儲存這幾個數。然後每一步在陣列中任選兩個數,對它們進行其中一種運算:+、-、*、/(注意,減法和除法不滿足交換律),並在原陣列中刪除選出的那兩個數,把運算結果新增到陣列中。經過這一步後,陣列的長度就會-1。依此類推,直到陣列的長度變為1,搜尋結束,陣列中剩下的那個元素就是結果,將它與之前得到的結果進行比較,選取更優的結果。

這裡作一點小改進:

用一個vector來儲存每一步對數字的操作,這樣就可以看到具體的過程和步驟。下面的程式碼中,我用一個vector<int>來儲存每一步的操作。vector<int>大小為4*(m-1),m為輸入的數字的個數。vector以四個數字為一個分組代表一步操作,第一個和第二個數字表示運算元,第三個數字表示結果,第四個數字表示操作符:0為+、1為-、2為*、3為/。

#include <iostream>
#include <vector>

using namespace std;

void search(vector<int> left, int &result, vector<int>& operators, vector<int> tmp_operators, int target)
{
	if (left.size() == 1) {
		//left中只剩一個元素,搜尋結束,比較結果,選取更優的那個
		if (left[0] <= target && left[0] > result) {
			result = left[0];
			operators = tmp_operators;
		}
	}
	else {
		//在left中選兩個數字,對它們進行+、-、*、/操作
		//+ - * /分別用0 1 2 3表示
		vector<int> tmp_left, tmp_tmpoperators;
		for (int i = 0; i < left.size(); i++) {
			for (int j = i + 1; j < left.size(); j++) {
				tmp_left = left;
				int tmp1 = tmp_left[i], tmp2 = tmp_left[j];
				tmp_left.erase(tmp_left.begin() + j);
				// +,tmp1和tmp2即使次序換了,結果不變
				tmp_tmpoperators = tmp_operators;
				tmp_left[i] = tmp1 + tmp2;
				tmp_tmpoperators.push_back(tmp1);
				tmp_tmpoperators.push_back(tmp2);
				tmp_tmpoperators.push_back(tmp1+tmp2);
				tmp_tmpoperators.push_back(0);
				search(tmp_left, result, operators, tmp_tmpoperators, target);

				// -,這裡要注意,tmp1-tmp2和tmp2-tmp1是不同的結果
				tmp_tmpoperators = tmp_operators;
				tmp_tmpoperators.push_back(tmp1);
				tmp_tmpoperators.push_back(tmp2);
				tmp_tmpoperators.push_back(tmp1 - tmp2);
				tmp_tmpoperators.push_back(1);
				tmp_left[i] = tmp1 - tmp2;
				search(tmp_left, result, operators, tmp_tmpoperators, target);

				tmp_tmpoperators = tmp_operators;
				tmp_tmpoperators.push_back(tmp2);
				tmp_tmpoperators.push_back(tmp1);
				tmp_tmpoperators.push_back(tmp2 - tmp1);
				tmp_tmpoperators.push_back(1);
				tmp_left[i] = tmp2 - tmp1;
				search(tmp_left, result, operators, tmp_tmpoperators, target);

				// *,tmp1和tmp2即使次序換了,結果不變
				tmp_tmpoperators = tmp_operators;
				tmp_tmpoperators.push_back(tmp1);
				tmp_tmpoperators.push_back(tmp2);
				tmp_tmpoperators.push_back(tmp1 * tmp2);
				tmp_tmpoperators.push_back(2);
				tmp_left[i] = tmp1 * tmp2;
				search(tmp_left, result, operators, tmp_tmpoperators, target);

				// /,這裡要注意,tmp1/tmp2和tmp2/tmp1是不同的結果
				if (tmp2 != 0 && tmp1%tmp2 == 0) {
					tmp_tmpoperators = tmp_operators;
					tmp_tmpoperators.push_back(tmp1);
					tmp_tmpoperators.push_back(tmp2);
					tmp_tmpoperators.push_back(tmp1 / tmp2);
					tmp_tmpoperators.push_back(3);
					tmp_left[i] = tmp1 / tmp2;
					search(tmp_left, result, operators, tmp_tmpoperators, target);
				}
				if (tmp1 != 0 && tmp2%tmp1 == 0) {
					tmp_tmpoperators = tmp_operators;
					tmp_tmpoperators.push_back(tmp2);
					tmp_tmpoperators.push_back(tmp1);
					tmp_tmpoperators.push_back(tmp2 / tmp1);
					tmp_tmpoperators.push_back(3);
					tmp_left[i] = tmp2 / tmp1;
					search(tmp_left, result, operators, tmp_tmpoperators, target);
				}
			}
		}
	}
}

int main()
{
	int m;
	cout << "輸入數字的個數:" << endl;
	cin >> m;
	vector<int> num(m);
	int target;
	int res = INT_MIN;
	cout << "輸入" << m << "個數字:" << endl;
	for (int i = 0; i < m; i++) {
		cin >> num[i];
	}
	cout << "輸入目標數:" << endl;
	cin >> target;
	vector<int> finaloperators, tmpoperators;
	search(num, res, finaloperators, tmpoperators, target);
	cout << "顯示過程:" << endl;
	for (int i = 0; i < m - 1; i++) {
		cout << finaloperators[i * 4] << ' ';
		if (finaloperators[i * 4 + 3] == 0) cout << '+' << ' ';
		else if (finaloperators[i * 4 + 3] == 1) cout << '-' << ' ';
		else if (finaloperators[i * 4 + 3] == 2) cout << '*' << ' ';
		else if (finaloperators[i * 4 + 3] == 3) cout << '/' << ' ';
		cout << finaloperators[i * 4 + 1] << " = " << finaloperators[i * 4 + 2] << endl;
	}
	system("pause");
	return 0;
}


相關文章