码迷,mamicode.com
首页 > 其他好文 > 详细

poj 1011/2362 dfs+剪枝(拼木棍)

时间:2015-02-28 14:46:23      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:

题意:乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。(2362是1011的特例,问一堆木棍能否拼成正方形)

思路:dfs+剪枝。其中剪枝具有相当的技巧性,其中一个地方的剪枝没有想到导致tle多次。

几个明显的剪枝点(设ans为最终的答案):

1、ans>=这堆木棍的最大长度

2、ans<=这堆木棍长度的总和

3、ans必可以被这堆木棍长度总和整除

4、对木棍由长到短排序,先考虑长的能有效剪枝

两个不明显但是最重要的剪枝点,缺一不可:

5、如果某次刚刚加入长度为x的木棍而随后搜索失败,则接下来的搜索只需搜比x小得木棍即可(代码中pre变量的作用)。

6、在每次构建新的长度为ans的木棍时,检查新棒的第一根s[i],若在搜索完所有木棍后都无法组合,则说明s[i]无法在当前组合方式下组合,不用往下搜索(因为再怎么搜索s[i]都不会加入到任何一个木棍当中)。代码中if(!from) return 0;这句话的作用。

1011:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define N 65
int s[N],f[3000],n,used[3005],res[6][100];
int sum,len,stick,perlen;
int cmp(const void* a,const void* b){
    return (*(int*)b) - (*(int*)a);
}
void factor(int b,int n){
    int i;
    for(i = b,len=0;i<=n;i++)
        if(n%i==0)
            f[++len] = i;
}
int dfs(int now,int from,int num){//当前木棍已经拼好的长度/从第几个木棍开始搜/已经拼好的木棍数量
    int i,pre;
    if(num == stick)
        return 1;
    if(now == perlen)
        return dfs(0,0,num+1);
    for(i = from,pre=0;i<n;i++)
        if(!used[i] && s[i]!=pre && now+s[i]<=perlen){
            used[i] = 1;
            if(dfs(now+s[i],i+1,num))
                return 1;
            used[i] = 0;
            pre = s[i];             //剪枝5,最重要的剪枝之一
            if(!from)               //剪枝6,最重要的剪枝之二
                return 0;
        }
    return 0;
}
int main(){
    while(scanf("%d",&n)&&n){
        int i;
        sum = 0;
        for(i = 0;i<n;i++){
            scanf("%d",&s[i]);
            sum += s[i];
        }
        qsort(s,n,sizeof(int),cmp); //满足剪枝4
        factor(s[0],sum);           //筛出因数,也即满足剪枝1~3
        for(i = 1;i<len;i++){
            memset(used,0,sizeof(used));
            stick = sum/f[i];       //当前搜索下得棍子数量
            perlen = f[i];          //当前搜索下的每根棍子长度
            if(dfs(0,0,0))
                break;
        }
        printf("%d\n",f[i]);
    }
    return 0;
}


2362:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int s[25],used[25];
int T,n,sum;
int cmp(const void* a,const void* b){
    return (*(int*)b)-(*(int*)a);
}
int dfs(int now,int from,int num){
    int i,pre;
    if(num == 4)
        return 1;
    if(now == sum/4)
        return dfs(0,0,num+1);
    for(i = from,pre=0;i<n;i++)
        if(!used[i] && s[i]!=pre && now+s[i]<=sum/4){
            used[i] = 1;
            pre = s[i];
            if(dfs(now+s[i],i+1,num))
                return 1;
            used[i] = 0;
            if(!from)
                return 0;
        }
    return 0;
}
int main(){
    scanf("%d",&T);
    while(T--){
        int i;
        memset(used,0,sizeof(used));
        scanf("%d",&n);
        for(i = sum = 0;i<n;i++){
            scanf("%d",&s[i]);
            sum += s[i];
        }
        qsort(s,n,sizeof(int),cmp);
        if(sum%4==0 && dfs(0,0,0))
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}



poj 1011/2362 dfs+剪枝(拼木棍)

标签:

原文地址:http://blog.csdn.net/dumeichen/article/details/43983197

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!