这个搜索做得比较早了….
11.1下午来机房开始搞这个暴搜,结果一直TLE&&WA
后来放了会没再管,11.3号早上又想了起来
然后就开始了悲惨的WA之路QAQ:
题是好题,是我太弱了…..
这道题的思路:
暴力枚举
我们枚举目标长度,当目标长度可以整除给出木棍长度之和的时候,我们再去判断这些木棍是否可以拼成该长度,这比枚举木棍根数要快并且更容易想到优化
(别问我怎么知道的,说多了都是泪)
但是裸暴力会超时,所以需要剪枝优化
1.首先很显然的一个剪枝,就是贪心,先将木棍从长到短排序,然后拼的时候先枚举长木棍的组合,因为长木棍限制更高,能够很快排除不少情况
2.然后我们可以在枚举目标木棍长度的时候,从给出木棍最长的开始到所有长度总和结束,因为显然目标木棍长度必然大于或等于数据给出的最长木棍长度
3.如果当前长度为0(第一层搜索),完成之后直接返回
4.在拼接木棍的的时候,相同长度的木棍之前用过,记录一下,下次直接continue
5…………………………………………………………………………………………..
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
int n,u;
int osu;
int len[105];
int totlen;
int ans = 0x3ffffff;
bool used[105];
inline int read()
{
char ch;
int f = 1;
int data = 0;
while(ch < '0'||ch > '9')
{
ch = getchar();
if(ch == '-')
f = -1;
}
do{
data = data*10+ch-'0';
ch = getchar();
}while(ch <= '9'&&ch >= '0');
return f*data;
}
bool cmp(const int a,const int b) { return a > b;}
inline bool dfs(int s,int nowlen,int viv)
{
bool bj;
if(nowlen == 0) bj = true;
else bj = false;
if(s == u) return true;
for(int i = viv;i <= n;i++)
{
if(used[i] == 1) continue;
if(nowlen + len[i] == osu)
{
used[i] = 1;
if(dfs(s+1,0,0)) return true;
used[i] = 0;
return false;
}
else if(nowlen + len[i] < osu)
{
used[i] = 1;
if(dfs(s,nowlen+len[i],i)) return true;
used[i] = 0;
if(bj == true) return false;
}
}
return false;
}
int main()
{
n = read();
for(int i = 1;i <= n;i++)
{
len[i] = read();
totlen += len[i];
}
sort(len+1,len+1+n,cmp);
for(int i = len[1];i <= totlen;i++)
{
if(totlen%i == 0)
{
osu = i;
u = totlen/i;
memset(used,0,sizeof(used));
if(dfs(1,0,0)) { ans = min(ans,i); continue;}
}
}
printf("%d\n",min(ans,totlen));
return 0;
}
THE END
By Peacefuldoge