二维平面深度优先-POJ 1020 Anniversary Cake

Posted 一米阳光213

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二维平面深度优先-POJ 1020 Anniversary Cake相关的知识,希望对你有一定的参考价值。

思路分析:

AC 代码: 16 ms

// 思路:这个问题没有巧妙的思路,于是只有贪心:能放下就放下,凑失败了就换一个。 
// 将大蛋糕人为划分为 SIZE * SIZE 个小格子,然后“从上到下,从左到右”依次填充大蛋糕。 

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
/*************** 全局变量 ******************/
char G[42][42];
int SIZE, n;			// 大蛋糕尺寸为 SIZE * SIZE,小蛋糕有 n 个
int cases;				// 测试用例的数量
int a[18];				// 所有小蛋糕的边长
bool visit_a[18];		// 所有小蛋糕被使用的情况
int col[42];			// 记载每一列被占用的格子数
bool visit_map[18];		// 所有小蛋糕被使用的情况,是否被使用了
bool is_OK;			// 本问题是否可解

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

int min(int a, int b)
	return a > b ? b : a;


// used_cakes: 已经使用的小蛋糕数量
// col 是核心的数据,描述了当前大蛋糕被填充的情况
// 
void dfs(int used_cakes)
	// Step 1: Termination condition
	if (used_cakes == n || is_OK == true)
		is_OK = true;
		return;
	
	// Step 2: 确定搜索范围
	// 根据剪枝1,从前往后选
	for (int i = 0; i < n && is_OK==false; i++)
		// Step 3: 排除无效的候选对象
		if (visit_a[i] == true) continue;
		// 从前往后找,找某一列其占用格子数最少
		// 坑:要找首次出现的占用格子数最少的列,所以,搜索的顺序应该是从后往前找,或者判断条件为 < 而不是 <= (细节)
		int min_ind = -1, min_val = 999999;
		for (int j = 0; j <SIZE; j++)
		if (col[j] < min_val) 
			min_ind = j;
			min_val = col[j];
		
		if ( SIZE - col[min_ind] < a[i] || min_ind + a[i] -1 >= SIZE || col[min_ind+a[i]-1] != col[min_ind] ) 
			continue;   // 为了加速程序,此处快速判断


		int w_x = 0;		// 水平方向能容纳的最大宽度
		int w_y = 0;		// 垂直方向能容纳的最大宽度
		int w = 0;			// 综合来看,当前能容纳的最大宽度
		for (int j = min_ind; j < SIZE;j++)
		if (col[j] <= min_val)
			w_x++;
		else
			break;
		w_y = SIZE - col[min_ind];
		w = min(w_x, w_y);
		// 判断是否能放得下
		if (a[i] > w) continue;

		// Step 4: 访问当前结点(即,使用当前小蛋糕)
		visit_a[i] = true;
		int new_val = col[min_ind] + a[i];
		for (int j = min_ind; j <= min_ind + a[i] - 1; j++)
			col[j] += a[i]; // 之所以不是 col[j] += a[i],是考虑到了像俄罗斯方块一样,前一层有缺口
		// Step 5: 继续下一步的搜索
		dfs(used_cakes + 1);
		if (is_OK == true) return;
		// Step 6: 放弃使用当前这个小蛋糕!
		for (int j = min_ind; j <= min_ind + a[i] - 1; j++)
			col[j] -= a[i];
		visit_a[i] = false;
	


// used_cakes: 已经使用的小蛋糕数量
// col 是核心的数据,描述了当前大蛋糕被填充的情况
// 
void dfs_fast(int used_cakes)
	// Step 1: Termination condition
	if (used_cakes == n || is_OK == true)
		is_OK = true;
		return;
	
	// Step 2: 确定搜索范围
	// 剪枝:如果尺寸为 x 的蛋糕,导致了失败,则后面跳过所有尺寸为 x 的蛋糕
	int failure_size = -1;
	for (int i = 0; i < n && is_OK == false; i++)
		// Step 3: 排除无效的候选对象
		if (visit_a[i] == true || a[i] == failure_size) continue;
		// 从前往后找,找某一列其占用格子数最少
		// 坑:要找首次出现的占用格子数最少的列,所以,搜索的顺序应该是从后往前找,或者判断条件为 < 而不是 <= (细节)
		int min_ind = -1, min_val = 999999;
		for (int j = 0; j <SIZE; j++)
		if (col[j] < min_val) 
			min_ind = j;
			min_val = col[j];
		
		if (SIZE - col[min_ind] < a[i] || min_ind + a[i] - 1 >= SIZE || col[min_ind + a[i] - 1] != col[min_ind])
			continue;   // 为了加速程序,此处快速判断


		int w_x = 0;		// 水平方向能容纳的最大宽度
		int w_y = 0;		// 垂直方向能容纳的最大宽度
		int w = 0;			// 综合来看,当前能容纳的最大宽度
		for (int j = min_ind; j < SIZE; j++)
		if (col[j] <= min_val)
			w_x++;
		else
			break;
		w_y = SIZE - col[min_ind];
		w = min(w_x, w_y);
		// 判断是否能放得下
		if (a[i] > w) continue;

		// Step 4: 访问当前结点(即,使用当前小蛋糕)
		visit_a[i] = true;
		int new_val = col[min_ind] + a[i];
		for (int j = min_ind; j <= min_ind + a[i] - 1; j++)
			col[j] += a[i]; // 之所以不是 col[j] += a[i],是考虑到了像俄罗斯方块一样,前一层有缺口
		// Step 5: 继续下一步的搜索
		dfs_fast(used_cakes + 1);
		if (is_OK == true)
			return;
		else if (used_cakes == 0)
			return;
		else
			failure_size = a[i];
		// Step 6: 放弃使用当前这个小蛋糕!
		for (int j = min_ind; j <= min_ind + a[i] - 1; j++)
			col[j] -= a[i];
		visit_a[i] = false;
	


int main(int argc, char * argv[])

	
	cin >> cases;
	while (cases--)
		/*************** Input ****************/
		// Initialization
		memset(G, 0, sizeof(G));
		memset(a, 0, sizeof(a));
		memset(visit_a, 0, sizeof(G));
		memset(col, 0, sizeof(col));

		is_OK = false;
		// Input
		int area = 0;
		int num_big_cakes = 0;
		scanf("%d%d", &SIZE, &n);
		for (int i = 0; i < n; i++)
		
			scanf("%d", &a[i]);
			area += a[i] * a[i];
			if (a[i] > SIZE / 2) num_big_cakes++;
		
		if (area != SIZE * SIZE || num_big_cakes > 1) 
			cout << "HUTUTU!" << endl;
			continue;
		
		// Sort
		sort(a, a + n, cmp);

		/*************** Process ****************/
		dfs_fast(0);

		/*************** Output ****************/
		if (is_OK)
			cout << "KHOOOOB!" << endl;
		else
			cout << "HUTUTU!" << endl;
	

	return 0;


 

以上是关于二维平面深度优先-POJ 1020 Anniversary Cake的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2362 Square 深度优先

POJ2488 深度优先搜索+回溯

[深度优先搜索] POJ 1426 Find The Multiple

[深度优先搜索] POJ 3620 Avoid The Lakes

LeetCode 1020 飞地的数量[dfs] HERODING的LeetCode之路

图论DFS(Depth First Search)Algorithm深度优先搜索遍历空间平面图选择路径,networkx,Python