poj2362 dfs 剪枝 比水题难的题

来源:互联网 发布:淘宝子账号可以开店吗 编辑:程序博客网 时间:2024/05/02 04:43

这道题tel了一晚上。。看了题解后。。终于A掉了,题目大意是:给出若干根各种长度的棍子,问它们能否拼接成正方形(每根都要用上)。

首先求出棍子长度的和sum。

剪枝1:sum%4!=0 则答案一定为no。

若sum%4==0,则棍子要组合出四根长度为 siz=sum/4 的边。

剪枝2:只要判断能组合出3条边,答案即为yes。

所有棍子长度按从大到小顺序排序,因为越长的棍子与其它棍子组合的数目越少。DFS时,从长的棍子开始与它之后的棍子相加,直到长度为siz;

剪枝3:若其中最长的棍子长度>siz,则答案为no。

剪枝4:若当前棍组合失败,从其后与其不等的棍开始搜索。

剪枝5:若当前棍组合失败,并且此棍是这条边选入的第一根棍,则直接返回,不继续往后搜索。(此剪枝优化程度实际非常大)

以下为代码:

<pre name="code" class="cpp">#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>using namespace std;int m,siz,flag=0,a[40],b[40];bool cmp(int x,int y){    return x>y;}void dfs(int len,int num,int k) //len为当前长度,num为当前已凑边数,k记录选棍开始时的位置。{    if(num==3) { flag=1; return ; }    int ret=-1;    for(int i=k;i<m;i++){        if(flag) return ;        if(b[i] || ret==a[i])continue; //ret记录上一根无法组合的棍子        b[i]=1; //标记        if(len+a[i]<siz) dfs(len+a[i],num,i+1),ret=a[i];        if(len+a[i]==siz) dfs(0,num+1,0),ret=a[i];        b[i]=0; //还原        if(len==0) return ;  //剪枝5,这个在poj1011中意义重大。    }}int main(){  //  freopen("in.txt","r",stdin);    int n;    scanf("%d",&n);    while(n--){        int sum=0;        scanf("%d",&m);        memset(a,0,sizeof(a));        memset(b,0,sizeof(b));        flag=0;        for(int i=0;i<m;i++){            scanf("%d",&a[i]);            sum+=a[i];        }        if(sum%4!=0){ // 剪枝1            printf("no\n");        }        else{            siz=sum/4;            if(a[0]>siz){  //剪枝3               printf("no\n");               continue;            }            sort(a,a+m,cmp);            dfs(0,0,0);            if(flag)                printf("yes\n");            else                printf("no\n");        }    }    return 0;}


                                             
0 0
原创粉丝点击