题解 P1120 【小木棍 [数据加强版]】

· · 题解

虽说这数据加强,但原版是紫题,原版

废话不多说,直接开始

这题显然是一道搜索题(标签上写了

无优化搜索

从小到大枚举答案(有个小优化,如果和不能整除此答案就跳过

设原始木棍根数为cnt(cnt=sum/len)

三个状态

1.已经拼好的木棍根数

2.当前长度

3.使用情况

我们每次搜索只需找到尚未使用的木棍(来尝试拼接),此时搜索一下新的状态

两个边界

1.成功拼好(可以输出答案了)

2.无法拼接(返回上次拼接状态)

无优化搜索完结撒花

虽不AC,却不用动脑子的好方法!!!

有优化搜索

搜索的优化(众所皆知

1.优化搜索顺序(此题需要

2.排除等效冗余(此题需要

3.可行性剪枝

4.最优性剪枝

5.记忆化搜索

优化搜索顺序!

我们可以将长度从大到小排序,优先尝试一下长的木棍

可以优化的原因:

如图所示(虽然有点丑)

我们从长的木棍开始合并或是从短的木棍开始合并长度一致,因此只需搜索其中一种

排除等效冗余

1.假设长度为x的木棍拼接失败,那么和为x的一堆木棍(一根都是如此)拼接也必然失败(状态和前面的状态一致)

2.如果已拼好的木棍长度为x,那么如果长度为y的无法向此拼接。下一堆已拼好的木棍如果长度也为x,y也一定不能向此拼接

3.用一根木棍总比用一堆木棍好(搜索之贪心

完整代码:code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll read()
{
    ll r=0,f=1;char c=getchar();
    while((c<'0'||c>'9')&&(c!='-')) c=getchar();
    if(c=='-') f=-1,c=getchar();
    while(c>='0'&&c<='9') r=r*10+c-'0',c=getchar();
    return r*f; 
}
ll a[101],v[101],n,len,cnt;
bool dfs(ll stick,ll cab,ll last)
{
    if(stick>cnt) return true; 
    if(cab==len) return dfs(stick+1,0,1);//往下一个搜 
    ll failess=0;
    for(int i=last;i<=n;i++)
     if(!v[i]&&cab+a[i]<=len&&failess!=a[i])
     {
        v[i]=1;
        if(dfs(stick,cab+a[i],i+1)) return true;
        failess=a[i];
        v[i]=0;
        if(cab==0||cab+a[i]==len) return false;
     }
     return false;
}
ll cmp(ll a,ll b)
{
    return a>b;
}
int main()
{
//  freopen("data.in","r",stdin);
//  freopen("data.out","w",stdout);
    n=read();
    ll sum=0,val=0;
    for(int i=1;i<=n;i++)
    {
        ll b=read();
        if(b>50) continue;
        a[i]=b;
        sum+=a[i];
        val=max(val,a[i]);
    }
    sort(a+1,a+n+1,cmp);
    for(len=val;len<=sum;len++)
    {
        if(sum%len) continue;
        cnt=sum/len;
        memset(v,0,sizeof(v));
        if(dfs(1,0,1)) break;
    }
    cout<<len<<endl;
    return 0;
}