PKU 2362 Square(dfs+剪枝)

题目的意思很清楚,给一些边的边长,判断能不能构成一个正方形。直接dfs过不了,要加一点剪枝才可以。
1.所有边长的和应该是4的倍数,否则不肯能构成正方形,这一点很容易想到。
2.必须按一定顺序搜索,不然会有很多重复,比如你从前面搜的时候,后面的有些不满足条件,那么搜后面时候就没必要再去搜前面的这些,这一点很重要,我是按边长递减的顺序搜的,这样就可以避免很多重复搜,还有搜到之后就不用回溯,这一点让我TLE了好几次,这时可以剪到200ms左右。
3.还有一点也很简单,就是这些边中最长的边要小于要拼的这个正方形的边长的,加上这一点可以剪到16ms了
4.要想达到0ms,我觉的还要加上一点,其实还有很多重复搜的,比如,从3搜无法拼成一条边,那么后面就没有必要从3开时搜了,直接跳过即可,这一点一直没很好的实现,还在改进。
 
PKU  2362  Square    http://acm.pku.edu.cn/JudgeOnline/problem?id=2362

Source Code

Problem: 2362  User: zhouxc
Memory: 204K  Time: 16MS
Language: C++  Result: Accepted


#include "iostream"

using namespace std;

int test,n,s[21];
int L,edge;
bool visited[21],flag;
int comp(const void *p1,const void *p2)
{
      return  *(int *)p1 <*(int *)p2;
}     

void Dfs(int cunt,int r,int length)
{
      
      // cout<<cunt<<" "<<r<<" "<<length<<endl;
       visited[r]=true;   
       if(cunt==4)
           flag=true;
       else if(!length)                    //当边拼成边长为edge时,表示拼好了一条边
       {
             length=edge;
             cunt++;                       //所拼成长度为edge的边数加一
             for(int i=1;i<n;i++)           //从未拼的边中选择下一条最长的边进行搜索
                if(!visited[i])
                    Dfs(cunt,i,length-s[i]);
       }   
       for(int i=r+1;i<n;i++)               //按边长递增的顺序搜索
       {
             if(!visited[i]&&length-s[i]>=0)   
                  Dfs(cunt,i,length-s[i]);
       }
       if(!flag)                           //当未拼成正方形时,回溯
       {
                visited[r]=false;
                cunt--;
       }       
      
}       
int main()
{
       
        scanf("%d",&test);
        while(test--)
        {      
                int sum=0;int M=0;
                scanf("%d",&n);
                for(int i=0;i<n;i++)
                {         
                      scanf("%d",&s[i]);
                      sum+=s[i];
                      visited[i]=false;
                      if(M<s[i])
                         M=s[i];
                }
                edge=sum/4;
                if(sum%4==0&&M<=edge)     //判断可否构成正方形
                {
                    flag=false;
                    qsort(s,n,sizeof(s[0]),comp);  //对边进行递减排序
                    Dfs(1,0,edge-s[0]);          //从最长的边开始搜索
                    if(flag)
                        printf("yes/n");
                    else
                        printf("no/n");   
                } 
                else
                    printf("no/n"); 
                   
        }          
               return 0;
}       

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值