POJ 2362 Square(搜索+剪枝)

来源:互联网 发布:linux命令文件命名 编辑:程序博客网 时间:2024/06/05 11:45

题目链接:点击打开链接

题意:给定一些木棍,是否能拼成正方形(木棍不能折断)?

思路:搜索,由题意,木棍要分别能组成四个边,不多不少。

读取完数据,所有木棍的长度和要能整除4,而且最长的木棍不能超过边的长度,先做这俩处理再搜索,能节省时间。

搜索时,顺序搜索每一条的组成情况,需要注意的是,为了不重复搜索,当前边选择木棍时,下一个处理的木棍的下标要比当前的大,而不能从最小的下标再开始选择,即使之前的边没被标记,也不能搜索回去,因为这是组合问题而不是排列问题,搜索回去就产生重复了,费时费力,比如,当前边一二步已经选择了2,4号木棍,然后无法搜索下去了,退回到了第一步,在第一步再去选择,选了4号,再第二步时,若是没那条规定,还是会选择2号木棍,所以“当前边下一个处理的木棍的下标要比当前的大”这条规则很重要。

还有,为了减少搜索的层数,读完数据先对木棍按照长度由大到小排序,这样每次先处理总是先处理长边,有减少搜索层数的可能性。

搜索过程中,还有一个重要的剪枝操作,若是当前方案能满足,不用搜完第四条边的组成再判断出来,搜到第四条边时就能得到判断了,因为进入搜索的前提是数值上能平均分配,若是已经找到了 若干木棍不多不少不折断 的组成前三条边的方案,那么剩余的一条边肯定是由余下的木棍组成的了。

// POJ 2362 Square.cpp 运行/限制:63ms/3000ms#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;int m,len,s[25],book[25];bool cmp(const int & a, const int &b) {return a > b;}bool dfs(int num, int loc, int length) {//当前边 当前木棍 当前边已找到的木棍的长度和if (num == 4) return true;for (int i = loc; i < m; i++) {//从loc开始,不是0if (!book[i]) {book[i] = 1;//选择后做标记bool re = false;if (length + s[i] == len) re = dfs(num + 1, 0, 0);//下一条边else if (length + s[i] < len) re = dfs(num, i + 1, length + s[i]);//继续当前边if (re) return re;book[i] = 0;//取消标记}}return false;}int main(){bool re;int n,sum;scanf("%d", &n);while (n--) {sum = 0;memset(book, 0, sizeof(book));scanf("%d", &m);for (int i = 0; i < m; i++) {scanf("%d", &s[i]);sum += s[i];}len = sum / 4;sort(s, s + m,cmp);if (sum % 4 || s[0] > len) re = false;else re = dfs(1, 0, 0);puts(re ? "yes" : "no");}    return 0;}



原创粉丝点击