poj 1011 小木棍

这个剪枝也是够了,不过不愧是搜索经典题,做完此题之后,感觉对深搜有了更多的理解,感觉学动规之前一定要学搜索,好的搜索题一定需要你好好的定义状态,在这里一定要把状态的知识学扎实了

再来说小木棍,小木棍有一个基础剪枝,就是找到上界和下界的位置

剪枝一:先得拼大的

剪枝二:如果一根新的长度没有拼成功,那么这个长度就不可用

剪枝三:在拼的过程中,如果中间有一段有相同的部分,并且一个没有成功,后面的不用尝试的

ps:洛谷的题目好坑

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=65;
int a[maxn],vis[maxn],n,num,ans;
int cmp(int a,int b)
{
    return a>b;
}
bool dfs(int res,int curn,int pos)
{ 
    bool flag=false;
    if(res==ans)  flag=true;//表示还没有开始拼接 
    if(a[n]>res) return false;
    if(curn==num) return true; 
    for(int i=pos;i<=n;i++)
    { 
        if(vis[i]==false&&a[i]==res)
        {
            vis[i]=true;
            if(dfs(ans,curn+1,1)) return true;//这里只能这样写,dfs才能连上 
            vis[i]=false;//拼接不成功  回溯 
            return false;//这里可以剪枝吗? 
        }else if(vis[i]==false&&a[i]<res)
                {
                    vis[i]=true;
                    if(dfs(res-a[i],curn,i+1)) return true;
                    vis[i]=false;
                    if(flag==true) return false;
                    while(a[i]==a[i+1]) i++;//如果前一个没有拼接成功,那么和他相同的也成功不了 
                }       
    }
    return false;//dfs循环断层的问题 
} 
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        memset(vis,0,sizeof(vis));
        memset(a,0,sizeof(a));
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>50) {n--,i--;}
            else sum=sum+a[i];
        }    
        sort(a+1,a+1+n,cmp);
        for(int i=a[1];i<=sum;i++)
        {
            if(sum%i==0) 
            {
                ans=i; 
                num=sum/i;
                if(dfs(ans,0,1)) 
                {
                    printf("%d\n",ans);
                    break;    
                }
                
            }    
        } 
    }
}

 

posted @ 2017-08-20 21:47  xinyimama  阅读(145)  评论(0)    收藏  举报