Fork me on GitHub

P1120 小木棍 [数据加强版]

https://www.luogu.org/problem/show?pid=1120#sub
枚举最小长度(从max–>sum),用dfs来判断,如果能成功就可以,退出即可。
dfs中有好多高深的剪枝!!
先将长度降序排序,便于剪枝。

剪枝:
判断当前的len时
1).如果在前面已经建造这一根长木棒的一部分的基础上如果这跟小木棒不能成功,那么和它长度相同的一定也不成功。
2).如果正好这跟小木棒再放上能够建成一根长木棒,而且不成功,那么当前枚举的长木棒len就一定不能成功,return 0;
3).若木棍X是旧一组的最后一根,旧一组拼完后,发现新一组无法完成,就不需要再枚举比木棍X小的木棍了;即当前枚举的长木棒len就一定不能成功,return 0;

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm> 
#include<cmath>
using namespace std;
int N,a[101],n,sum,maxn;
int f[101];
bool cmp(int x,int y){return x>y;} 
bool dfs(int x,int len,int now,int num)//当前枚举的最小长度--现在已经拼完的长度--现在拼完的根数  
{
    if(num==sum/len) return 1;

    if(now==len)
    if(dfs(1,len,0,num+1)) return 1;

    for(int i=x;i<=n;i++)
    if(!f[i]&&now+a[i]<=len)
    {
        f[i]=1;
        if(dfs(i+1,len,now+a[i],num)) return 1;
        f[i]=0;

        if(a[i]==len-now||now==0) break;
        while(a[i]==a[i+1]) i++;
    }
    return 0;
}
int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
    {
        int x;scanf("%d",&x);
        if(x<=50){
            a[++n]=x,sum+=x;
            maxn=max(maxn,x);
        }
    }
    sort(a+1,a+n+1,cmp);
    for(int i=maxn;i<=sum;i++)
    if(sum%i==0){
        memset(f,0,sizeof(f));
        if(dfs(1,i,0,0)){
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}
posted @ 2017-09-24 17:48  primes  阅读(209)  评论(0编辑  收藏  举报