POJ 1020.Anniversary Cake

题目:http://poj.org/problem?id=1020

AC代码(C++):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define INF 0x3f3f3f3f
#define INF0 0x7fffffff
#define eps 1e-5
typedef unsigned long long ull;
typedef long long ll;

using namespace std;

int s, n;
int cnt[11];
int col[50];
bool ans;

void dfs(int dep) {
	if (dep == n) {
		ans = true;
		return;
	}
	for (int k = 10; k >= 1; k--) {
		if (cnt[k] == 0)continue;
		int mincol, min = INF;
		for (int i = 1; i <= s; i++) {
			if (col[i] < min) {
				min = col[i];
				mincol = i;
			}
		}
		if (col[mincol] + k>s)continue;
		for (int i = mincol; i <= s; i++) {
			if (col[i] > col[mincol])break;
			if (i - mincol + 1 == k) {
				for (int j = mincol; j <= i; j++)col[j] += k;
				cnt[k]--;
				dfs(dep + 1);
				if (ans)return;
				cnt[k]++;
				for (int j = mincol; j <= i; j++)col[j] -= k;
				break;
			}
		}
	}
}

int main() {
	int t;
	cin >> t;
	while (t--) {
		cin >> s >> n;
		int tmp;
		memset(cnt, 0, sizeof(cnt));
		int err = 0;
		int total = 0;
		for (int i = 0; i < n; i++) {
			cin >> tmp;
			cnt[tmp]++;
			total += tmp*tmp;
			if (tmp > s / 2)err++;
		}
		if (err > 1 || total != s*s) {
			cout << "HUTUTU!\n";
			continue;
		}
		memset(col, 0, sizeof(col));
		ans = false;
		dfs(0);
		if (ans)cout << "KHOOOOB!\n";
		else cout << "HUTUTU!\n";
	}

	//system("pause");
}

总结: 深搜. 深搜本身不难, 难的是如何去思考问题. 一开始自己写这个题目, 第一眼看出来应该是深搜, 广搜不现实因为要储存大量的状态. 刚开始深搜的思路是见缝插针, 将大蛋糕看做一个盒子, 往里面放小蛋糕, 从上到下从左往右摆, 如果有缝隙, 则判断缝隙能否容纳蛋糕, 能则放进去. 这样的思路非常朴素, 想法和编程实现都不难, 所以理所当然的TLE了. 后来看了网上流传最广的题解, 将盒子分成40列, 用一维数组来储存每一列的状态. 当时觉得很奇怪, 这样放不会出现空隙吗? 仔细理解了一下, 发现这个办法确实很妙.

把盒子立起来, 从上到下是行, 从左往右是列, 然后像俄罗斯方块那样从上面往下落小蛋糕, 选择合适的位置落下. 唯一不同于俄罗斯方块的地方是, 小蛋糕的形状是可以自己选择的. 每次找一个最矮的列, 然后往它左右两边看, 看下有多少列和它一样矮, 记为宽度, 然后从剩余的小蛋糕中任选一个填进去, 小蛋糕的大小应小于宽度. 如此循环直到放不下或者放完. 因为每次选择的都是最矮的列, 所以不可能出现缝隙, 即使要出现缝隙, 也会因为无法往最矮的列中插入蛋糕而回溯.

为什么这样的思路会让程序快这么多? 按照朴素思想, 只要看见缝隙就放蛋糕, 那么到最后蛋糕的摆放肯定很乱, 甚至从途中就开始出现无法填满的缝隙, 而这样的不可能为解的状态以及摆放时缝隙的判断就浪费了大量的时间. 所以这题考的就是, 如何消除摆放蛋糕过程中缝隙所带来的影响. 如果放着空隙不管, 肯定会搜索大量无用状态导致TLE, 那么对空隙管理的最好办法就是消除空隙, 摆的时候就不会出现空隙, 从问题的源头解决它. 至于如何想出这样的摆放方法来消除空隙, 就是智商和经验的问题了, 我等菜鸡只能多借鉴学习了.

你可能感兴趣的:(poj)