1. 程式人生 > >【題解】 洛谷1120 小木棍 [資料加強版]

【題解】 洛谷1120 小木棍 [資料加強版]

原題


剪枝好題,可以有以下9個剪枝(基本上都是可行性剪枝,還有一些搜尋順序的剪枝),這是一道除了生日蛋糕以外的剪枝好題當然不會告訴你Biscuit46花了1h做這道題目

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<map>
#define ll long long
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline int gi(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
int n,tot,a[70],Max,s,t,L,flag,vis[70],sum[70];
void dfs(int stick,int Length,int last){
    if(Length==L){dfs(stick+1,0,1);return;}
    if(stick==t-1){//Cut3
        printf("%d\n",L);exit(0);
    }
    for(int i=last;i<=n;i++)//Cut4
        if(!vis[i] && a[i]+Length<=L){//Cut5
            if(a[i]==a[i-1] && !vis[i-1])continue;//Cut6如果長度相同且上一個沒選,顯然這個也不選。
            if(Length+sum[i]<L)return;//Cut7,字尾和優化一下(因為按照從大到小排序)
            vis[i]=1;
            dfs(stick,a[i]+Length,i+1);
            vis[i]=0;
            if(!Length)return;//Cut8
            if(Length+a[i]==L)return;//Cut9
        }
}
bool cmp(int a,int b){
    return a>b;
}
void init(){scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(x>50)continue;
        a[++tot]=x;Max=max(Max,x);
        s+=x;
    }
    sort(a+1,a+n+1,cmp);//Cut1
    for(int i=n;i>=1;i--)
        sum[i]=sum[i+1]+a[i];
    n=tot;
}
int main(){
    int i,j,k,m;
    init();
    for(i=Max;i<=s/2;i++){//Cut2,顯然不會選s/2+1~s-1的長度(因為無法湊出)
        if(s%i!=0)continue;
        t=s/i;L=i;
        dfs(0,0,1);
    }
    printf("%d\n",s);
    return 0;
}