zoukankan      html  css  js  c++  java
  • poj1011Stick(dfs+剪枝)

    题目链接:http://poj.org/problem?id=1011

    Dfs中状态的转移是重点
    1.分析问题
    问题:将n个部分拼接成sum/h个长度为h的木棍。部分分别为stk[i]
    2.分析解状态
    r=sum/h
    因为h是固定的,不作为状态
    初始状态:
    取了0个部分。剩n个部分,正在拼的木棍有h还未拼完,剩r个木棍要拼
    取一个部分,还剩n-1个部分,正在拼的木棍还剩h-stk[i]还未拼完,还剩r个木棍要拼
    设正在拼的木棍还剩hr  
    取k个部分,拼完一根木棍,还剩n-k个部分,正在拼的木棍还有0还未拼完,还hr-1个木棍要拼
    设剩下rs木棍要拼,还剩nr个部分
    解状态:
    拼完了r根木棍,还剩0个部分,正在拼的木棍有0还未拼完,还剩0个木棍要拼
    3.写出状态转移dfs(剩n-k个部分,还有hr个部分要拼,还剩rs个木棍要拼)
    dfs(n,h,r)->dfs(nr,hr,rs)->dfs(0,0,0)    (hr>stk[next])
     
    dfs(nr,hr,rs)表示在该状态时,能否拼成功,返回值为bool型
    当nr==0&&hr==0&&rs==0
    则返回true
    当nr!=0&&hr==0&&rs!=0
    此时说明拼完了一根木棍,
    return dfs(nr-1,h,rs-1)
    当nr!=0&&hr!=0&&rs!=0
    for循环选择了一个部分i以后
    return dfs(nr-1,hr-stk[i],rs)
     
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    /*
    对木棍的长度h有三个限制
    1:所有parts的最大长度maxL<=h  且h<=parts长度和sum 
    2:h|sum
    3:h<=50 
    显然所有的限制之中最重要的是找到sum的因子
    因子还要大于等于maxL且小于等于50(暂时先不管这个) 
    */
    const int maxn=65;
    int n,sum,maxL;
    int stk[maxn];
    int h[maxn];
    bool vis[maxn];
    bool cmp(int a,int b){
        return a>b;
    }
    
    /*剪枝有四
    1:
    如果选择前面的部分之后不成功(vis[i-1]==0),而当前项又与前面项相同(stk[i]==stk[i-1]),则说明该项不可能,跳过(前提是i!=1) 
    2:
    如果部分i是一根木棒的第一块,那么若i不可取,不需要去遍历其他的数来替换部分i,可直接跳过 
    3:
    如果用部分i去填补一根木棍,正好使其拼接完成,但是dfs表明选择部分i之后不能拼接, 则不必找其他部分来替换,直接将失败反馈给前一个部分的选择 
    4:
    一根木棍从前到后的每一块都要保证长度从大到小,即当前选择的块不能比前一块大 
    5:
    如果只剩一根木棍还没拼,那肯定成功 
    */ 
    bool dfs(int nr,int hr,int rs,int h){//dfs(剩下的部分数,木棍剩下未拼接的长度hr, 剩下还没拼的木棍数rs,木棍的长度h) 
        if(nr==0&&hr==0&&rs==0) 
            return true;
        else if(nr!=0&&hr==0 )//说明已经拼接完一个木棍了,接下来要拼接新的 
        {
            hr=h;
            rs--;
        }
        else if (rs==1)
            return true;
        //都没有的话,说明正在选择可取部分来填充木棍剩余的长度 
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&hr>=stk[i])//判断是否可取  
            {    
                vis[i]=1;
                if(i!=1&&!vis[i-1]&&vis[i-1]==vis[i])
                    continue;
                if(dfs(nr-1,hr-stk[i],rs,h))//如果取这个部分可以成功 
                    return true;
                else//否则,部分i不可取 
                {     
                    vis[i]=0;
                    if(hr==stk[i]||hr==h)//拼接完一个木棍之后,选择下一个木棍的第一块,若第一块不可取,则直接退出,去修改上一个木棍 
                        return false;
                }
            }
        }//遍历了所有可取部分,没有一个能成功的,则记得返回失败
        return false; 
    }
    
    int main (){
        while(cin>>n)
        {
            if(!n)
                break;
            sum=maxL=0;
            for(int i=1;i<=n;i++)
            {
                cin>>stk[i];
                if(maxL<stk[i])
                    maxL=stk[i];
                sum+=stk[i];
            }
            //找因子 
            memset(h,0,sizeof(h));
            int cur=1;
            if(n==1)//注意考虑n==1的情况
            {
                cout<<sum<<endl;
                continue;
            }
            else{
                for(int i=1;i*i<=sum;i++)        //h中包含小于maxL的因子 
                    if(sum%i==0) 
                        h[cur++]=i;
                for(int i=cur-1;i>0;i--) 
                    h[cur++]=sum/h[i];    //h中的因子元素从小到大 
            }
            sort(stk+1,stk+n+1,cmp); //从大到小
            for(int i=1;i<cur;i++) //遍历所有的因子 
            {
                memset(vis,0,sizeof(vis));
                if(h[i]<maxL)
                    continue;
                if(dfs(n,h[i],sum/h[i],h[i]))//如果这个木棍长度可以被拼接 
                {
                    cout<<h[i]<<endl;
                    break;
                }
            }//一定有一个因子能够满足(sum自身) 
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    海思HI3516A开发板顺利上线
    android WIFI信息获取
    五------Jsp九大内置对象。
    在Windows下搭建Apacheserver
    基于ContentObserver来动态取消或加入屏幕超时任务
    使用Intent的Flag设置启动參数
    IntelliJ IDEA像Eclipse一样打开多个项目
    怎样让IE支持自己定义协议
    《TCP/IP具体解释卷2:实现》笔记--协议控制块
    POJ2029:Get Many Persimmon Trees(二维树状数组)
  • 原文地址:https://www.cnblogs.com/neverchanje/p/3552453.html
Copyright © 2011-2022 走看看