不是题解!不是题解!不是题解!重要的事情说三遍!纯属个人学习笔记!
传送门:P1120
AC代码:
#include<bits/stdc++.h>
using namespace std;
int s[100],vis[100],next1[100];
bool ok;
int number,len;
int sum;
inline int read()
{
int f=1,w=0;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
w=w*10+ch-'0';
ch=getchar();
}
return f*w;
}
bool cmp(int a,int b)
{return a>b;}
void dfs(int k,int last,int rest)
{
int i;
if(!rest)
{
if(k==number)
{ok=1;return;}
for( i=1;i<=sum;i++)
{
if(!vis[i])break;
}
vis[i]=1;
dfs(k+1,i,len-s[i]);
vis[i]=0;
if(ok)return ;
}
int l=last+1,r=sum,mid;
while(l<r)
{
mid=(l+r)>>1;
if(s[mid]<=rest)r=mid-1;
else l=mid+1;
}
//cout<<rest<<' '<<t<<endl;
for(int i=l;i<=sum;i++)
{
if(!vis[i])
{
vis[i]=1;
dfs(k,i,rest-s[i]);
vis[i]=0;
if(ok)return ;
if(rest==s[i]||rest==len)return ;
i=next1[i];
if(i==sum)return ;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
n=read();
//cout<<n<<endl;
sum=0;
int ans=0;
for(int i=1;i<=n;i++)
{
int t;t=read();
if(t>50)continue;
s[++sum]=t;
ans+=t;
}
sort(s+1,s+1+sum,cmp);
next1[sum]=sum;
for(int i=sum-1;i;i--)
{
if(s[i]==s[i+1])next1[i]=next1[i+1];
else next1[i]=i;
}
for(len=s[1];len<=ans/2;len++)
{
if(ans%len!=0)continue;
number=ans/len;
ok=0;
vis[1]=1;
dfs(1,1,len-s[1]);
vis[1]=0;
if(ok)
{cout<<len<<endl;return 0;}
}
cout<<ans<<endl;
return 0;
}
写搜索对于我来说是一件很痛苦的事情,因为都知道这是搜索,但如果剪枝(优化)剪不好就是无限被T。并且这类搜索题如果出现一些神仙优化,剪枝就是脑子爆炸。
所以这里就拿这道题来聊聊思路。
1.如果直接暴力搜索该怎么写?
不难分析出原始木块的长度一定处于 max(s[i])
到 sum
之间,所以我们可以用原始长度为操作点,分析每一种长度是否满足情况,如果出现满足条件的长度,就直接输出,因为可以保证输出的是最小值。
确定了原始长度len
之后,就要分析,哪些木棍组合可以组合成原始长度为len
的木棍 。
这里最暴力可以想到搜索,找出所有可能的情况,并且分析是否可满足初始条件。
2,确定了最暴力的解法之后,优化成了最大boss。
- 出现的木棍长度可能有重复,如果已知
len (i)
不满足条件,下一次搜索的应该是与len(i)
不同的数,所以可以建立一个next数组,避免重复。
next数组的建立也很有意思,在上次模拟赛中有一个签到题就要用到next数组进行优化,但那时候我还不会,就卡了很久。
这里给出的代码可以当成板子来记:
for(int i=sum-1;i;i--)
{
if(s[i]==s[i+1])next1[i]=next1[i+1];
else next1[i]=i;
}
- 在遍历搜索的时候,不难想到,每次搜索都要搜索比现在位置后的数,不用搜索比现在位置还前的数字,因为如果下一个数字出现在当前位置之前就一定在之前的搜索中查询过。所以每次向后找就行了,
- 在找下一个木棍的时候,利用二分的方法可以快速查找到可行的位置,如果不用二分会被T掉一个点。
- 本题最神仙的是
if(rest==s[i]||rest==len)return ;
这个点我绝对想不到。