大致题意:

有一堆任意长度的小棒子,问他们能否构成一个正方形。

 

解题思路:

与 POJ 1011 Sticks 神似啊,但是简单一点。

// POJ 1011 的精简版
//

#include \"stdafx.h\"
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int n, a[22];
bool visit[22];			// 所有小棍子的长度
int is_OK;				// 1: 成功   0:待定   -1:必定失败
int target_len;			// 正方形的边长

bool cmp(int a, int b){
	return a > b;
}

// return:
// true: 成功拼凑
// false: 拼凑失败
bool dfs(int start_index, int finished_sticks, int remaining_length){
	// Step 1: Termination conditions
	if (finished_sticks == 3){   // 剪枝:只要拼完了3根 target_len 棍子,就可以肯定,一定成功
		return true;
	}

	// Step 2: Search range
	//int failure_length = -1;
	for (int i = start_index; i < n; i++){
		// Step 3: 排除无效的搜索对象
		//if ( visit[i] ==true || a[i] > remaining_length || a[i] == failure_length) continue;
		if (visit[i]) 
			continue;

		// Step 4: 使用当前的对象,又要分两种情况:刚好凑了一个边长,还是仍有剩余的长度需要拼凑
		visit[i] = true;
		if (a[i] == remaining_length){ // 新开一根
			if (dfs(0, finished_sticks + 1, target_len))
				return true;
		}
		else if( a[i] < remaining_length){						   // 继续往下搜索
			if (dfs(i, finished_sticks, remaining_length - a[i]))
				return true;
		}

		// Step 5: 放弃使用当前的对象
		visit[i] = false;
		// 剪枝:如果第一根小棍子失败了,直接放弃!必定失败
		//if (remaining_length == target_len || start_index ==0 ){
		//	return false;
		//}
	}
	return false;
} 

int main(int argc, char * argv[])
{
	int cases;
	cin >> cases;
	while (cases--){
		scanf(\"%d\", &n);
		int sum = 0;
		for (int i = 0; i < n; i++)
		{
			scanf(\"%d\", &a[i]);
			sum += a[i];
		}
		is_OK = 0;
		memset(visit, 0, sizeof(visit));
		// 剪枝1:简单的判断一下可行性
		if (sum % 4 != 0 || n<4)
		{
			cout << \"no\" << endl;
			continue;
		}
		else
			target_len = sum / 4;
		// 剪枝2:将所有小棍子按长度从大到小排序
		sort(a, a + n, cmp);
		// 剪枝3:如果有小棍子长度 > target_len ,直接失败
		if (a[0] > target_len){
			cout << \"no\" << endl;
			continue;
		}

		// 深度优先搜索
		is_OK = dfs( 0, 0, target_len);
		//is_OK = dfs_std(a, visit, 0, 0, 0);

		if (is_OK == true )
			cout << \"yes\" << endl;
		else
			cout << \"no\" << endl;
	}
	return 0;
}

 

收藏 打印