• 洛谷P1120 小木棍 [数据加强版]


    P1120 小木棍 [数据加强版]

    题目描述

    乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。

    现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

    给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

    输入输出格式

    输入格式:

    输入文件共有二行。

    第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65

    (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)

    第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

    输出格式:

    输出文件仅一行,表示要求的原始木棍的最小可能长度

    输入输出样例

    输入样例#1:
    9
    5 2 1 5 2 1 5 2 1
    
    输出样例#1:
    6

    说明

    2017/08/05

    数据时限修改:

    -#17 #20 #22 #27 四组数据时限500ms

    -#21 #24 #28 #29 #30五组数据时限1000ms

    其他时限改为200ms(请放心食用)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 70
    using namespace std;
    int n,a[maxn],sum,b[3251],cnt,nn;
    bool vis[maxn],flag;
    void dfs(int now,int num,int limit,int s){//当前和,已经选了多少个木棍,枚举到的答案 
        if(flag)return;
        if(now==0&&(sum-s)%limit)return;
        if(now==0&&num==nn){flag=1;return;}
        for(int i=1;i<=nn;i++){
            if(!vis[i]&&a[i]+now<=limit){
                vis[i]=1;
                if(a[i]+now==limit)dfs(0,num+1,limit,s+a[i]);
                else dfs(now+a[i],num+1,limit,s+a[i]);
                vis[i]=0;
            }
        }
    }
    int main(){
        freopen("Cola.txt","r",stdin);
        scanf("%d",&n);
        int x;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            if(x>50)continue;
            a[++nn]=x;
            sum+=a[nn];
        }
        for(int i=1;i*i<=sum;i++)
            if(sum%i==0){
                b[++cnt]=i;
                if(i*i==sum)break;
                b[++cnt]=sum/i;
            }
        sort(b+1,b+cnt+1);
        for(int i=1;i<=cnt;i++){
            memset(vis,0,sizeof(vis));
            dfs(0,0,b[i],0);
            if(flag){
                printf("%d",b[i]);
                return 0;
            }
        }
    }
    27分 裸的搜索
    /*
    显然,dfs搜索的是木棍总长的因数。 
    
       1. 我们搜索的木棍长度假设是合法的,那么每一组达到了当前长度的木棍组合,一定是存在的。
    例如样例:5 2 1 5 2 1 5 2 1 比如说我搜索木棍总长的因数6,我们目前搜的木棍组是(5,1),如果这个6的木棍长度是合法的话,那么必有一组木棍组合是(5,1).
    所以当我们搜索的木棍组是(5,1)但在之后的搜索中搜不出长度为6的木棍组,那么这个木棍长度就是非法的。
    推广到所有长度,即只要如果当前木棍组达到了木棍长度,却在之后的搜索中的木棍组并不能达到这个木棍长度,那么这个木棍长度就是不合法的。 
       
       2. sort排序从大到小改变搜索顺序,可以更快(因为我们一旦找到合法数据就可以退出)。 
    
       3. 我们要从上次搜索的终点往后搜索,所有的原理都离不开第一点。
       
       4.如果当前这个木棍组的长度+当前的a[i] (a[i]为我们一开始输入的每根被砍碎的木棍的长度),还不能达到当前我们搜索的木棍长度
         那么值相同的a[i]都不能使这个木棍组的长达到木棍组长度,我们的sort排序也为这点提供了基础。
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define maxn 70
    using namespace std;
    int n,a[maxn],cnt,mx,s;
    bool cmp(int x,int y){return x>y;}
    bool vis[maxn];
    void dfs(int ans,int sum,int goal,int now){
        if(sum*goal==s){printf("%d",goal);exit(0);}
        if(s-ans<a[cnt])return;
        if(ans==goal){dfs(0,sum+1,goal,1);return;}
        for(int i=now;i<=cnt;i++){
            if(!vis[i]&&a[i]+ans<=goal){
                vis[i]=1;
                dfs(ans+a[i],sum,goal,i+1);
                vis[i]=0;
                if(ans+a[i]==goal||ans==0)break;
                while(a[i]==a[i+1])i++;
            }
        }
    }
    int main(){
        scanf("%d",&n);
        int x;
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            if(x>50)continue;
            a[++cnt]=x;s+=a[cnt];mx=max(mx,a[cnt]);
        }
        sort(a+1,a+cnt+1,cmp);
        for(int i=mx;i<=s/2;i++)
            if(s%i==0)dfs(0,0,i,1);
        printf("%d",s);
        return 0;
    }
    100分 各种剪枝
  • 相关阅读:
    【Atcoder Beginner Contest 178】E-F
    【Poj-3436】ACM Computer Factory 最大流
    【Codeforces Round #662 (Div. 2) 】C. Pinkie Pie Eats Patty-cakes 贪心
    【秋叶收藏集】
    【第二届全国高校绿色计算大赛 预赛第二阶段(Python)】Tarjan + 最短路
    【模拟】第二届全国高校绿色计算大赛 预赛第二阶段(Python) 文本编辑器
    【Codeforces】#658 D.Unmerge DP
    【Codeforces】#658 C2.Prefix Flip(Hard Version)
    【Codeforces】#658 B.Sequential Nim 博弈
    【Codeforces】#657 C.Choosing flowers 枚举 二分
  • 原文地址:https://www.cnblogs.com/thmyl/p/7650388.html
Copyright © 2020-2023  润新知