计蒜客-等边三角形-抽象dfs剪枝思路过程

题目链接
动手之前要想好解空间树,解空间树是决定复杂度的关键,极端情况的微弱剪枝效果往往不佳。

一开始的想法(相对麻烦,可以直接跳过)

三条边的长度已知(sum),按照边的长度作为dfs的参数a

  1. 遍历每条边,未被使用过且sum - a大于当前边,则将该木棍纳入该边
  2. 当边长符合题目要求时,判断此时是第几条满足要求的边
  3. 如果是第三条,则判断是否全部边都被使用,不是则判断为不可能,是则输出yes,结束
  4. 如果不是第三条满足要求边,则将当前边长归零,重复1-3过程

仅通过了8组测试样例

#include

using namespace std;
int cnt[25], n, sum, res, num;
bool vis[25];

void dfs(int a){
	if(a == sum){
		a = 0;
		res++;
		if(res == 3)
		{
			if(num == n)
				cout<<"yes"<<endl;
			else
				cout<<"no"<<endl;
			exit(0);
		}
		else
		{
			dfs(a);
			res--;
			a = sum;
		}
		return ;
	}
	for(int i = 0; i < n; i++){
		if(!vis[i] && sum - a >= cnt[i]){
			for(int j = 1; j <= 2; j++){
				if(j & 1){
					a += cnt[i];
					vis[i] = true;
					num++;
					dfs(a);
					num--;
					vis[i] = false;
					a -= cnt[i];
				}
			}
		}
	}
}

int main(){
	cin>>n;
	for(int i = 0; i < n; i++){
		scanf("%d", &cnt[i]);
		sum += cnt[i];
	}
	if(sum % 3 == 0){
		sum /= 3;
		memset(vis, false, sizeof(vis));
		dfs(0);
	}
	cout<<"no"<<endl;
	return 0;
}

改进之后的想法

解空间树实际上是一个高度为n的三叉树

  1. 层数i代表第i根木棍, 对每根木棍尝试放入三角形不同的三条边
  2. 当层数到达n层时,表示n根木棍均被放置,此时三边长若相等则成功,否则执行1步骤
  3. 对所有情况遍历后仍无解,则失败
    剪枝只是简单判断了一下纳入木棍后是否会大于所求等边三角形的边长,ac代码
#include

using namespace std;
int cnt[25], n, s[3], sum;
bool vis[25];
void dfs(int c){
	if(c == n){
		if(s[0] == s[1] && s[1] == s[2]){
			cout<<"yes"<<endl;
			exit(0);
		}
	}
		for(int j = 0; j < 3; j++){
			if(!vis[c] && sum - s[j] >= cnt[c]){
				s[j] += cnt[c];
				dfs(c + 1);
				s[j] -= cnt[c];
			}
		}
}
int main()
{
	cin>>n;
	for(int i = 0; i < n; i++){
		scanf("%d", &cnt[i]);
		sum += cnt[i];
	}
	sum /= 3;
	memset(s, 0, sizeof(s));
	dfs(0);
	cout<<"no"<<endl;
	return 0;
}

你可能感兴趣的:(acm,dfs,递归)