Poj2362 Square ——搜索+剪枝

This way

题意:

给你n个长度,问你这些长度是否能组成一个正方形

题解:

    相当于要把n个球放到四个篮子里,每个篮子里的球的值之和=sum/4.
    这个时间复杂度不是很好算,所以在确定用搜索来做这道题的时候需要尽可能地剪枝。首先是四条边我们只需要搜三条即可。那么我们想让搜的数量尽可能小的话,需要将值从大到小排序,这样如果第一条边需要的长度>1的时候,第四条边需要的长度>=2.并且如果有一个样例会让排序后第四条边的长度数量尽可能少的话,那么这个答案我们会在搜到中间的时候搜出来,而不会拖到最后。
    我们的思路是一条边一条边去组成,先搜第一条边,用过的长度标记一下,在回溯的时候给撤销。然后从大到小排序的另一个好处就是,对于当前这条边的组成的长度,前面搜过的就不会再搜了,我用了一个sta在参数里面就表示下一次枚举长度的时候从哪里开始。

#include
#include
#include
#include
using namespace std;
const int N=25;
int n,a[N],average,vis[N];
bool cmp(int x,int y){return x>y;}
bool dfs(int now,int sum,int sta){//现在到了now条边,和为sum,从第sta个数开始
    if(now==4)return 1;
    for(int i=sta;i<=n;i++){
        if(vis[i])continue;
        vis[i]=1;
        if(sum+a[i]<average&&dfs(now,sum+a[i],i+1))
            return 1;
        else if(sum+a[i]==average&&dfs(now+1,0,1))
            return 1;
        vis[i]=0;
    }
    return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        memset(vis,0,sizeof vis);
        average=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),average+=a[i];
        sort(a+1,a+1+n,cmp);//从大到小,这样就可以在dfs时候减小复杂度
        if(average%4||a[0]>average||n<4){
            printf("no\n");
            continue;
        }
        average/=4;
        printf("%s\n",dfs(1,0,1)?"yes":"no");
    }
    return 0;
}

你可能感兴趣的:(dfs,剪枝,深度优先,算法)