poj 2362Square(DFS)

           开始超时,上网搜了下,发现要剪枝才行……附上搜到的剪枝方法:    

剪枝1:
所有木棍的长度必须能被4整除

剪枝2:
最长的木棍不能长于正方形的边长

这两个是最容易想到的,用上这两个可以79ms通过

剪枝3:
同样长度的木棍的同样数量的组合只搜索一次。
这个剪枝需要将木棍从大到小排列,在搜索的时候加一句代码就行了,代码很巧妙。
由于数据问题,这个剪枝貌似不管用。

剪枝4:
每条边的木棍按照从大到小的顺序拼接
如果某条木棍不能够作为某边的第一条木棍,那比它短的也不行
想一想还是可以理解,后面的边始终会用到这条长的棍子,那时候可供选择的木棍更少
所以在前面的边拼不成,在后面的边更加拼不成
这个剪枝非常牛逼,不知道谁想出来的,代码只需要一句。太牛逼了。
由于数据的N比较小,这个剪枝相当管用。

无法实现的理想化剪枝:
如果在枚举中,发现用一条长的棍子枚举失败,那么几条短的棍子组成同样长度的棍子也必然不用试验。
这个很理想,但是实现的代价很大。

题目描述:

1011的弱版……给一堆木棒,每根木棒有个长度,求是否能使这些木棒分成4堆,每堆总长度相等

解题报告:

显然可以求得每堆的总长度len=all/4;

然后开始填充len……方法和1011一样……用了几个减枝

1。如果4不能整除all,不用搜索,不可能

2。如果最大木棒的长度大于len,不用搜索,不可能

3。对所有木帮排序,填充时先用长度长的,因为长度长的木帮显然不如短的用得灵活

4。如果已经找到答案,尽快返回上一层

5。判断当前长度是否大于每段的长度,小于就不用搜索了,显然不可能

6。相同长度的木棒不用搜索多次

7。从最接近并小于这根木棒的木棒开始搜索,这根之前的木棒显然都用过了

8。判断当前剩下的段数是否小于4-d,不用搜索,不可能

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int len[21];
int visited[21];
int N, M;
//start:开始的木棍标号 l:已组合的长度, num:已组合成功的目标正方形的边数, length:目标正方形的边长
int DFS(int start, int l, int num, int length)
{
    if(num==4) return 1;
    int i;
    for(i=start; i<M; i++)
    {
        if( visited[i]==0 )
        {
            if( l+len[i]==length )
            {
                visited[i]=1;
                if( DFS(0, 0, num+1, length )) return 1;
                visited[i]=0;
            }
            else if( l+len[i]<length)
            {
                visited[i]=1;
                if( DFS(i+1, l+len[i], num, length )) return 1;
                visited[i]=0;
            }
              while( len[i]==len[i+1])//某长度的木棍不能完成某个子问题,那么和它一样长的也不能完成
                  i++;
        }
    }
    return 0;
}
bool cmp(int a, int b)
{
	return a>b;
}
int main()
{
    int i, sum, length;
    cin>>N;
    while( N-- )
    {
        sum=0;//sum记录所有木棍的长度和
        cin>>M;
        memset(visited, 0, sizeof(visited));
        for(i=0; i<M; i++)
        {
             cin>>len[i];
             sum+=len[i];
        }
        sort(len, len+M, cmp);
        length=sum/4;
        if( sum%4==0 && len[0]<=length)//木棍总和能被4整除且最长的木棍小于正方形边长
        {
            if( DFS(0, 0,0,length))
               cout<<"yes"<<endl;
            else
               cout<<"no"<<endl;
        }
         else //如果不可以,肯定不能组成正方形
            cout<<"no"<<endl;
    }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值