• poj1011(DFS+剪枝)


    题目链接:https://vjudge.net/problem/POJ-1011

    题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最小长度。

    思路:经典的DFS剪枝题,这道题的剪枝技巧很关键。

      数据不大,可以想到枚举木棍所有可能的长度,然后利用dfs来查找所有可能的搭配情况,dfs的参数len表示当前的木棍长度,rest表示还需要的长度,pos表示当前搜到的下标,num表示原始木棍中剩余没有匹配的数量,搜索的终止条件为rest==0&&num==0,但直接这样做还是会超时,这道题有许多的剪枝技巧:

      1. 将序列降序排序,方便后面的剪枝。

      2. 枚举的范围是[Max,sum/2],其中Max为序列中的最大值,sum为序列和。

      3. 可能的长度只能是sum的约数。

      4. 深搜时,如果在寻找一条新木棍时使用了剩余木棍中最长的也不能满足条件,则直接返回。因为最长的一根一定要使用,不用的话后面也一直用不到,最终是无法成功匹配的。对应代码中的if(!rest)中的语句。

      5. 深搜时,如果当前木棍刚好使正在凑的木棍形成新木棍,但也不满足条件时,直接返回。比如你现在是3,使用3刚好能凑出一根新木棍,但使用之后后面仍无法满足条件,现在即使后面存在1 2,你使用1 2来凑出剩下的3也一定不能满足条件,因为1 2两条木棍比3更灵活,使用1 2都无法成功的话使用3更无法成功。对应代码if(a[i]==rest) break。

      6. 当前木棍长为x,使用x无法满足条件时,则可直接跳过后面所有长为x的木棍。对应代码while(a[i+1]==a[i]) ++i。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    int n,a[70],vis[70],ans;
    
    bool cmp(int x,int y){
        return x>y;
    }
    
    bool dfs(int len,int rest,int pos,int num){
        if(!rest&&!num){
            ans=len;
            return true;
        }
        if(!rest){
            rest=len;
            for(int i=0;i<n;++i){
                if(vis[i]) continue;
                vis[i]=1;
                if(dfs(len,rest-a[i],i+1,num-1))
                    return true;
                vis[i]=0;
                return false;
            }
        }
        for(int i=pos;i<n;++i){
            if(vis[i]) continue;
            if(a[i]<=rest){
                vis[i]=1;
                if(dfs(len,rest-a[i],i+1,num-1))
                    return true;
                vis[i]=0;
                if(a[i]==rest) break;
                while(a[i+1]==a[i]) ++i;
            }
        }
        return false;
    }
    
    int main(){
        while(scanf("%d",&n),n){
            int sum=0,flag=0;
            for(int i=0;i<n;++i){
                scanf("%d",&a[i]);
                sum+=a[i];
            }
            sort(a,a+n,cmp);
            memset(vis,0,sizeof(vis));
            for(int i=a[0];i<=sum/2;++i){
                if(sum%i==0){
                    if(dfs(i,i,0,n)){
                        flag=1;
                        break;
                    }
                }
            }
            if(flag)
                printf("%d
    ",ans);
            else
                printf("%d
    ",sum);
        }
        return 0;
    }

      

  • 相关阅读:
    bzoj1644 [Usaco2007 Oct]Obstacle Course 障碍训练课
    bzoj1640 [Usaco2007 Nov]Best Cow Line 队列变换
    bzoj1639 [Usaco2007 Mar]Monthly Expense 月度开支
    bzoj1637 [Usaco2007 Mar]Balanced Lineup
    bzoj1641 [Usaco2007 Nov]Cow Hurdles 奶牛跨栏
    bzoj1635 [Usaco2007 Jan]Tallest Cow 最高的牛
    bzoj1638 [Usaco2007 Mar]Cow Traffic 奶牛交通
    bzoj3407 [Usaco2009 Oct]Bessie's Weight Problem 贝茜的体重问题
    bzoj1631 [Usaco2007 Feb]Cow Party
    bzoj1632 [Usaco2007 Feb]Lilypad Pond
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10843742.html
Copyright © 2020-2023  润新知