这么多天没发博客真的对不起自己对不起大家对不起全世界......
课多大作业也多,思考人生理想心绪也不是很安稳,毕竟处在关键阶段。尽力就好吧。
废话不多说先入正题,对于1011这道题编程小白(可能是老白......)表示无能为力。
除了忙别的事儿这个题也是拖着学了三四天吧,因为本身对于递归就望而生畏,一遍一遍地重写代码直到不超时还是对递归熟练了很多。虽然非常菜鸡地还要用个flag来表示递归结束......但是好歹也是写出来了嘛......
这题是深度优先遍历的思想。
先上代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> sticks;
int fvisit[64]={0};
int resultlen;
int unitlen;
bool flag=false;
void dfs(int needlen,int begin){//dfs只要调用意味着实参代表的木棍在当前分支下一定有资格选上
fvisit[begin]=1;//标志位置为1,表示把begin对应的木棍选上
needlen-=sticks[begin];//剩余长度去掉选上的木棍长度
int begin1=begin;//begin1选定下一个木棍
if(needlen==0){//已经组成了一根木棍
int i;
for(i=0;i<sticks.size();i++){//找下一组木棍的开头
if(fvisit[i]==0){
begin1=i;
needlen=unitlen;
break;
}
}
if(i==sticks.size()){//没有没被选上的木棍了,此次unitlen成功
resultlen=unitlen;
flag=true;
fvisit[begin]=0;//fvisit恢复初始化状态
return;
}
dfs(needlen,begin1);//选下一个木棍
fvisit[begin]=0;//fvisit恢复初始化状态
return;
}
while(begin1<sticks.size()-1){//正在组成一根unitlen长的木棍
begin1++;
if(fvisit[begin1]==0&&sticks[begin1]<=needlen){//选定下一根小木棍
dfs(needlen,begin1);
if(flag){//此次unitlen成功
fvisit[begin]=0;//fvisit恢复初始化状态
return;
}
while(begin1<sticks.size()-1&&sticks[begin1]==sticks[begin1+1]){//还未成功,递归回溯回来继续尝试下一根木棍
begin1++;
}
}
}
fvisit[begin]=0;//fvisit恢复初始化状态
return;
}
bool cmp(int a,int b){
return a>b;
}
int main(){
int n;
scanf("%d",&n);
while(n!=0){//一组数据的处理
int len;
int sum=0;
while(n--){
scanf("%d",&len);
sticks.push_back(len);
sum+=len;
}
sort(sticks.begin(),sticks.end(),cmp);//棍长从大到小
int max=sticks[0];
for(unitlen=max;unitlen>=max&&unitlen<=sum;unitlen++){
resultlen=0;
if(sum%unitlen==0){
dfs(unitlen,0);
if(flag){//unitlen可以确定下来
flag=false;
break;
}
}
}
printf("%d\n",resultlen);
sticks.clear();
scanf("%d",&n);
}
return 0;
}
这道题第一个思想就是先考虑较长的木棍,后考虑较短的木棍。我尝试了一下,如果从小到大来排列,结果不会有问题,但是会超时。可能就是基于短木棍长度比较灵活的思想。但是我不知道为什么,我想不大清楚。查阅网上的博客,大家好像都觉得这个从大到小排列没有必要说,是常识,但是我想不大明白。
第二个思想是,木棍长度只可能在木棍最大值到木棍长度和区间内,这个道理倒是很好想通。
第三个思想就是剪枝,技巧是连续几个相同的数字要不成立就都不成立,不需要继续尝试,重复递归,浪费时间。
我的dfs函数大致思想是,参数为当前尝试的木棍长度(unitlen)还需要凑的木棍长度以及当前尝试选择的木棍(为了组成unitlen的木棍)下标。如果需要凑的长度已经是0,就说明已经凑成了一个长度为unitlen的木棍。否则,继续找寻满足条件可以凑长度的木棍。注意每次递归返回都要把fvisit标志数组恢复到没选当前木棍的样子。
觉得写的不是很清楚,非常悲催地感冒了,头疼,就先这样啦~
明天也是要好好写代码的一天!