码迷,mamicode.com
首页 > 其他好文 > 详细

小木棍 [数据加强版]

时间:2019-08-20 20:31:41      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:超过   增加   ref   names   visit   printf   href   原来   题意   

洛咕

双倍经验---多组数据

题意:乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50.现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度.给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度.

分析:首先读入的时候把长度大于50的自动过滤掉,剩下n根长度小于等于50的木棍,设这n根小木棍的长度和为\(tot\),长度最大的为\(val\).

我们直接从小到大枚举原始木棍的长度,并通过dfs判断是否合法即可.枚举的下界是一个小木棍的最大长度\(val\),上界是长度和\(tot\).设当前枚举的原始木棍的长度为\(len\),那么\(tot\)必然要能被\(len\)整除,否则不合法,若能够被整除,显然我们要是能够拼凑出\(sum=tot/len\)根长度为\(len\)的木棍就是合法答案.

接下来就只要考虑dfs的剪枝操作了.

一,我们把木棍长度从大到小排序,优先考虑较长的木棍,显然能减少状态数.

二,既然剪枝一已经把木棍排序了,那么我们干脆固定每次填入的木棍长度是递减的.这个只要dfs的变量增加一个last,表示当前从第last根木棍开始考虑就好了.

三,假设我们给一根"空"的 填入木棍,也就是当前的木棍长度\(cnt=0\),那么当填入\(a[i]\)后该搜索状态不合法,那么直接判定当前分支不合法,因为你把\(a[i]\)填入剩下的其它的"空"的,都会是不合法的.

四,跟三类似,如果我们当前填完了\(a[i]\)之后,填完了一个长度为len的木棍,发现该搜索状态不合法,那么直接判定当前分支不合法,因为你再用别的若干根短的木棍来代替\(a[i]\),那么接下来搜索下一根木棍还会是不合法的.

五,如果填入\(a[i]\)不合法,如果\(a[i+1]=a[i]\)那么直接不要考虑填.

这些剪枝真的是缺一不可.亲测~~~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=105;
int n,tot,val,sum,len;
int a[N],visit[N];
//当前正在拼第now跟木棒
//第now跟木棒已经拼出了长度cnt
//当前已经考虑到了第last根木棍
inline bool dfs(int now,int cnt,int last){
    if(now>sum)return true;//sum根木棒都拼完了
    if(cnt==len)return dfs(now+1,0,1);//当前这根拼完了
    int fail=0;//剪枝五用的
    for(int i=last;i<=n;++i){
        if(!visit[i]&&cnt+a[i]<=len&&fail!=a[i]){
            visit[i]=1;
            if(dfs(now,cnt+a[i],i+1))return true;
            fail=a[i];//记录不要填与a[i]相同长度的木棍了
            visit[i]=0;//回溯
            if(!cnt||cnt+a[i]==len)return false;//剪枝三,四
        }
    }
    return false;
}
int main(){
    int nn=read();
    for(int i=1;i<=nn;++i){
        int b=read();
        if(b<=50){//过滤不合法的木棍
            a[++n]=b;tot+=b;//记录长度和
            val=max(b,val);//比较最长木棍
        }
    }
    sort(a+1,a+n+1);reverse(a+1,a+n+1);//从大到小排序
    for(len=val;len<=tot;++len){//枚举原始木棍长度为len
        if(tot%len)continue;//不能整除肯定不合法
        sum=tot/len;//要拼凑出sum根木棍
        memset(visit,0,sizeof(visit));//初始化
        if(dfs(1,0,1)){
            printf("%d\n",len);
            break;
        }
    }
    return 0;
}

小木棍 [数据加强版]

标签:超过   增加   ref   names   visit   printf   href   原来   题意   

原文地址:https://www.cnblogs.com/PPXppx/p/11385261.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!