poj1011

这么多天没发博客真的对不起自己对不起大家对不起全世界......
课多大作业也多,思考人生理想心绪也不是很安稳,毕竟处在关键阶段。尽力就好吧。

废话不多说先入正题,对于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标志数组恢复到没选当前木棍的样子。
觉得写的不是很清楚,非常悲催地感冒了,头疼,就先这样啦~

明天也是要好好写代码的一天!

猜你喜欢

转载自blog.csdn.net/qq_33508759/article/details/80056474