DFS自学笔记以及一道典型题1103 Integer Factorization (30分)

关于参照《算法笔记》学习DFS时的一些自身理解

首先DFS是一种“出栈入栈”思想。
到达分岔口时入栈,离开分岔口(即该分岔口处所有可走路径都已遍历完成)或者死胡同时出栈。
这里附上我觉得对我理解帮助比较大的一篇博客

递归是用来解决该类问题的有利工具

毕竟递归即是系统利用系统栈来存放递归的每一层状态。因此其本质还是栈。
在使用递归时,递归式即为分岔口,递归边界即为死胡同。
拿Fibonacci数列举例来说,F(0)与F(1)是递归边界,也即“死胡同”,F(n)=F(n-1)+F(n-2) (n>=2) 是递归式,那么F(n)就可理解为一个分岔口。

一类DFS常见解决方法:

将问题的一个解看为一个序列,枚举这个序列的所有子序列(事先对序列中可能
出现的所有元素指定一个顺序,那么对于每个次序上的元素都有“选取/不选取”两个分岔口)—— 从中根据需要找出某个特征最优的子序列。

其实当我们解决深度优先搜索问题时,首先应该分析问题找出“分岔口”与“死胡同”,那么当确定问题可以用这类方法解决时,“分岔口”便非常容易找到,即为每个元素“选取”或“不选取”,那么死胡同即为题目中的一些约束条件,比如最后结果中一共有几个元素,或者最后结果的和不能超过多少。当然在这个过程中我们也可以把符合条件的解看成一个死胡同,只不过此时不是直接返回,而是先对结果进行存储或者相关处理

例如对于序列{1,2,3}来说 (假设题目要求按递增顺序输出结果),那么其子序列有{1}、{2}、{3}、{1,2},{1,3}、{2,3}、{1,2,3}。

拿其中的{1}举例来说:也即在第一个分岔口“是否选取第一个元素1”中,选择了“选取”这条岔路,在第二个分岔口“是否选取第二个元素2”时,选择了“不选取”这条岔路,在第三个分岔口“是否选取第三个元素3”时,选择了“不选取”这条岔路,此时已经处理了最后一个元素,那么就到达了一个死胡同(因为现在没有其他限制),也就产生了一种可能的结果序列{1}。那么退回到上一个分岔口,也即“是否选择第三元素3”,此时便该走“选取”这条岔路,便产生了{1,3}这一序列。

PAT (Advanced Level) Practice 1103 Integer Factorization (30分)

(参照了一些算法笔记的思路以及自己的简化)
在这里插入图片描述

int n, k, p,maxn=0;
vector<int> temp, ans;
int facs[410] = { 0 };
/**
深度优先搜索,index代表当前正要对哪个元素进行抉择选取,sum1为当前结果中各元素的平方和,
sum2位当前结果中各元素的和
*/
void DFS(int index, int sum1, int sum2,int num)
{

	if (sum1 == n && sum2 > maxn&&num==k) {
		ans = temp;
		maxn = sum2;
		return;
	}
	
	//剪枝操作,符合条件时才继续向深处遍历
	if (sum1 + facs[index] <= n&&num+1<=k) {
		temp.push_back(index);
		//由于一个子序列中一个元素可以重复多次,因此选取该元素后,下一个检验的还是该元素
		DFS(index,sum1 + facs[index], sum2 + index,num+1);
		temp.pop_back();
	}

	//不选取当前元素
	if(index>1)
	 DFS(index - 1, sum1, sum2,num);
}

int main()
{
	scanf("%d %d %d", &n, &k, &p);
  	
	int index;
	//先提前算出每个数指定次方的结果
	for (int i = 0;; i++) {
		if (pow(i, p) <= n) {
			facs[i] = pow(i, p);
			index = i;
		}
		else
			break;
	}
	//由于题目要求选择字典序最大的方案,那么从后往前遍历可以保证当出现两个结果序列元素值相等时,
	//保留字典序大的方案
	DFS(index, 0, 0,0);
	if (ans.size() == 0)
		printf("Impossible\n");
	else
	{
		printf("%d=%d^%d", n, ans[0], p);
			for (int i = 1; i < ans.size(); i++)
				printf(" + %d^%d",ans[i], p);
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值