• POJ 1011 Sticks dfs,剪枝 难度:2


    http://poj.org/problem?id=1011

    要把所给的集合分成几个集合,每个集合相加之和ans相等,且ans最小,因为这个和ans只在[1,64*50]内,所以可以用dfs一试

    首先ans需要满足两个条件1.可以被总集合的和sum整除 2.是总集合的某个子集的和 对于条件1,可以通过试除遍历 对于条件2,可以通过dp预筛选,这两个花费时间都不大

    接着搜索能不能划分成集合之和恰为ans的若干集合,

    1. 可以从大向小找,因为大的更不灵活,而且所有的元素都需要取到

    2.比如对于5,4,2,2,1 使用第一个2,向下找,没有找到答案,不用第一个2之后,也不需要再找第二,第三个2了

    如果之前找过相同的数字了,那么之后就不用再找相同的数字

    3.如果这次数字刚好组合成为一个ans,那么能不能组成由剩下的数字决定,也就是已经得到了一个新集合和为ans了,剩下的能够组成若干和为ans的集合则可以取ans,否则不能取ans

    #include <cstdio>
    #include<cstring>
    #include <algorithm>
    using namespace std;
    int a[64],n;
    bool cmp(int a,int b){return a>b;}
    bool reachable[64*51];
    bool used[64];
    bool dfs(int s,int tmp,int sub){
         //   printf("s:%d tmp:%d sub:%d
    ",s,tmp,sub);
            used[s]=true;
            tmp+=a[s];
            if(tmp>sub){// 不可能出现
                    puts("ERROR");
                    used[s]=false;
                    return false;
            }
            if(tmp==sub){//恰好成为一个和为ans的集合
                    for(int i=0;i<n;i++){
                            if(!used[i]){
                                    if(dfs(i,0,sub))return true;//dfs新的集合,直接返回剩下的元素能不能组合成若干和为ans的集合
                                    else {
                                            used[s]=false;
                                            return false;
                                    }
                            }
                    }
                    return true;//所有元素都被使用了
            }
            int f=-1;
            for(int i=s+1;i<n;i++){
                    if(f==a[i]||used[i]){continue;}//如果这个状态的这个函数已经找过相同的数
                    if(tmp+a[i]==sub){//直接返回剩下的元素的组合状态
                            if(dfs(i,tmp,sub))return true;
                            else {
                                    used[s]=false;
                                    return false;
                            }
                    }
                    else if(tmp+a[i]<sub){//可以试着添加进这个集合
                            if(dfs(i,tmp,sub))return true;
                    }
                    f=a[i];
            }
            used[s]=false;
            return false;
    }
    int main(){
            while(scanf("%d",&n)==1&&n){
                    int sum=0,mx=0;
                    memset(reachable,false,sizeof(reachable));
                    for(int i=0;i<n;i++){
                            scanf("%d",a+i);
                            sum+=a[i];
                            mx=max(a[i],mx);
                    }
                    reachable[a[n-1]]=true;
                    reachable[0]=true;
                    sort(a,a+n,cmp);//从大到小搜索
                    for(int i=n-2;i>=0;i--){
                            for(int j=0;j<sum&&j+a[i]<=sum;j++){
                                    if(reachable[j]){
                                            reachable[j+a[i]]=true;//reachable[i]=true i可以被总集合中的某些元素加和得到
                                    }
                            }
                    }
                    bool fnd=false;
                    for(int i=mx;i<sum;i++){
                            if(sum%i==0&&reachable[i]){
                                    memset(used,0,sizeof(used));
                                    if(dfs(0,0,i)){
                                            printf("%d
    ",i);
                                            fnd=true;
                                            break;
                                    }
                            }
                    }
                    if(!fnd)printf("%d
    ",sum);
            }
    
            return 0;
    }
    

      

  • 相关阅读:
    二维图像的DCT变换
    Shell脚本加密--shc/gzexe
    vim python插件--vim python mode
    移动端图片裁剪解决方案
    移动端压缩并ajax上传图片解决方案
    html5拖拽实现
    html5的触摸事件
    js循环添加事件的问题
    h5上传图片
    thinkphp加载第三方类库
  • 原文地址:https://www.cnblogs.com/xuesu/p/4349227.html
Copyright © 2020-2023  润新知