首页 > 代码库 > poj 1011 Sticks 【DFS】+【剪枝】

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;
}


题目链接:点击打开链接