这么多天没发博客真的对不起自己对不起大家对不起全世界......
课多大作业也多,思考人生理想心绪也不是很安稳,毕竟处在关键阶段。尽力就好吧。
废话不多说先入正题,对于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标志数组恢复到没选当前木棍的样子。
觉得写的不是很清楚,非常悲催地感冒了,头疼,就先这样啦~
明天也是要好好写代码的一天!