POJ Anniversary Cake (dfs,神剪)

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

题意:

首行是t,下面t行每行是一个case,第一个数s表示给你一个边长为s的正方形大蛋糕,第二个数n表示把这个大蛋糕分成n块小正方形蛋糕,后面跟n个数表示这n个蛋糕的边长。

问是否能刚好分完。是输出KHOOOOB! ,不是输出HUTUTU! 


个人感觉这道搜索题有些难...看了别人的代码才了解了思路。

参考博客:http://blog.csdn.net/lyy289065406/article/details/6683250   感谢!


大体的思路就是以一个col数组来标记每列已经占用了多少。然后先放大蛋糕,以左下优先的顺序去不断尝试切小蛋糕,切不了要求的则回溯。

根据数据可以推出大蛋糕最大的大小是40 * 40。

具体见代码。


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int s, n;
int sizenum[11]; //各大小小蛋糕的数量 
int col[41];   //该列被切了多少 
int dfs(int dep) {
	if(dep == n) return 1; //全切完退出 
	int minc = 50, pcol;
	int i;
	for(i = 1; i <= s; i++) {  //找到被切最少的列,因为要满足从下到上的原则 
		if(minc > col[i]) {
			minc = col[i];
			pcol = i;
		}
	}
	int size, p;
	for(size = 10; size > 0; size--) {  //从最大块开始尝试切下 
		if(sizenum[size] == 0) continue;
		if(s - col[pcol] >= size && s - pcol + 1 >= size) { //以该列为起点能切下这块大小 
			for(p = pcol; p <= pcol + size - 1; p++) {  //看该列以后所需的列是否也都满足被切条件 
				if(col[p] != col[pcol]) break;
			}
			if(p == pcol + size) {  //满足则切下,修改标记 
				for(p = pcol; p <= pcol + size - 1; p++) col[p] += size;
				sizenum[size]--;
				if(dfs(dep + 1)) return 1;  //若为假则下面回溯 
				sizenum[size]++;
				for(p = pcol; p <= pcol + size - 1; p++) col[p] -= size;
			}
		}
	}
	return 0;
}
int main () {
	int t;
	scanf("%d", &t);
	while(t--) {
		scanf("%d %d", &s, &n);
		memset(sizenum, 0, sizeof(sizenum));
		memset(col, 0, sizeof(col));
		int i, area = 0, sid;
		for(i = 1; i <= n; i++) {
			scanf("%d", &sid);
			area += sid * sid;
			sizenum[sid]++;
		}
		if(area != s * s) { //连面积都不相等直接退出 
			printf("HUTUTU!\n");
			continue;
		}
		if(dfs(0)) printf("KHOOOOB!\n");
		else printf("HUTUTU!\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值