poj 1011 Sticks 【DFS】+【剪枝】

题意:有未知根(长度一样)木棒(小于等于n),被猪脚任意的截成n段,猪脚(脑抽了)想知道被截之前的最短长度(我推测猪脚得了健忘症)。

这道题光理解题意就花了好久,大意就是任意根被截后的木棒拼到一起,能不能组成s(《=n)根的相同的木棒,

例:数据 9 

5 1 2 5 1 2 5 1 2

可以组成最短为6 的(5+1, 2+2+2)3根木棒。

策略:深搜。

不过要是传统的深搜的话,TLE妥妥的。所以要剪枝(所谓剪枝,就是多加几个限制条件)。

话不多说直接上代码。

代码1:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::sort;
int s[70], n;//n是被截成的段数
bool vis[70];
int cmp(int a, int b)
{
	return a > b;
}
int dfs(int len, int cur, int num)  //len是假设的答案,cur是构成答案长度的木棒所需要的,num,是剩余的木棒数
{
	if(cur ==0&&num ==0) return true;  //如果都满足条件,果断返回true
	if(cur == 0) cur =len; //如果满足了一根木棒,那么就继续构成下一根木棒(剪枝)
	int i;
	for(i = 0; i < n; i ++){
		if(vis[i]) continue;
		if(cur - s[i] >= 0){
			vis[i] = 1;
			if(dfs(len, cur-s[i], num-1)) return true;//如果构不成,果断返回false(剪枝)
			vis[i] = 0;
			if(s[i] == cur||cur == len) return false;//s[i]==cur是如果满足一根木棒的长度但是不能构成全部的,cur == len 是进行循环之后还是构不成   都要返回false(剪枝)
			while(s[i] == s[i+1]&&i+1 < n) ++i;//如果同等长度的不满足,就不用再继续该长度的了(剪枝)
		}
	}
	return false;
}
int main()
{
	int i;
	while(scanf("%d", &n), n){
		int sum = 0;
		for(i = 0; i < n; i ++){
			scanf("%d", &s[i]);
			sum += s[i];	
		}
		sort(s, s+n, cmp);//从大到小排序,对于程序更快,比如说因为我们考虑4的时候,如果4不满足构成满足条件的木棒,那么1和3组合肯定也不满足条件,那么我们4不满足条件的时候,我们就可以结束这次深搜了。
		for(i = s[0]; i <= sum; i ++){ //最大不可能超过总和,最小得大于这么多最长的
			if(sum %i == 0){
				memset(vis, 0, sizeof(vis));//每一次都要初始化
				if(dfs(i, 0, n)){  
					printf("%d\n", i);
					break;
				}
			}
		}
	}
	return 0;
}

代码2(此代码略。。学习了):

#include <stdio.h>
#include <string.h>
#include <algorithm>
using std::sort;
int s[70], ans, n;//ans就是最后的答案
bool vis[70];
int cmp(int a, int b)
{
	return a>b;
}
int dfs(int cou, int cur, int pos) //pos是当前的位置,
{
	if(cou == n) return true;
	if(cur > ans) return false;
	int i;
	for(i = pos; i < n; i ++){
		if(vis[i]) continue;
		if(cur + s[i] < ans){
			vis[i] = 1;
			if(dfs(cou+1, cur+s[i], i+1)) return true;
			vis[i] = 0;
			while(s[i] == s[i+1]&&i+1 < n) ++i;
			if(cur == 0) return false;
		}
		else if(cur + s[i] == ans){
			vis[i] = 1;
			if(dfs(cou+1, 0, 0)) return true;//如果构成了一根长为ans木棒,从s[0]开始再次查找
			vis[i] = 0;
			return false;	
		}
	}
	return false;
}
int main()
{
	int i;
	while(scanf("%d", &n), n){
		int sum = 0;
		for(i = 0; i < n; i ++){
			scanf("%d", &s[i]);
			sum += s[i];
		}
		sort(s, s+n, cmp);
		for(i = n; i > 0; i --){
			if(sum%i==0&&(sum/i) >= s[0]){
				memset(vis, 0, sizeof(vis));
				ans = sum/i;
				if(dfs(0, 0, 0)){
					printf("%d\n", ans);
					break;
				}
			}
		}
	}
	return 0;
}


题目链接:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值