【数据结构】经典习题自测(四)

对照本人有关数据结构专栏第四讲的内容,为了加强对栈的了解,我精心挑选如下习题,供有需要的读者参考

 其中具体函数可以参照我的上一条博客:【数据结构】五分钟自测主干知识(四) 

配合食用效果更佳~

http://t.csdnimg.cn/Gw0D4icon-default.png?t=N7T8http://t.csdnimg.cn/Gw0D4


例1 

        背包问题求解。假设有一个体积为T的背包和n个体积分别为w_1,w_2,\dots,w_n的物品,任意从 n个物品中抽取k个,使其恰好装满背包(体积之和为T),即w_{i1}+w_{i2}+\dots+w_{ik}=T


求解的这类问题需要给出所有可能的解,因此需要穷举所有的物品组合。那么怎样才
能遍历所有可能的组合而又简化编程代码呢?通常使用“回溯”的设计思想来实现。

首先将所有物品排成一列,然后顺序选取物品放入背包,如果当前选取的物品不能装入背包(即包中已有的物品体积加上当前选取的物品体积超出了T),则放弃它继续选取下一个物品,直至背包装满为止。如果装入某个物品后,剩下的物品都“不合适”再装入背包(即一直尝试到最后一个物品都不能放进背包),那么说明我们最后一个放进背包的物品“不合适”,需要取出它,并从它下一个物品继续尝试。如果某个物品放入背包后,恰巧装满背包,那么就需要输出当前的背包内物品作为一组解,然后再取出最后一个放进去的物品,从它下一个物品继续尝试下一个解。

这种从背包中取出最后一个放进去的物品再继续尝试的策略称为回溯。很显然,回溯时取出物品的次序和之前放入的次序刚好相反,最后放进去的最先被取出来,这和栈的“后进先出”特性是一致的。如果把背包用一个栈来表示,每次放入一个物品就是入栈,那么回溯时取出物品的操作实际上就是一个出栈操作。

还需要注意的问题是,入栈时栈元素的数据域内容不是物品的体积,而是物品排列的序号k,这样方便回溯时容易找到“下一个”序号的物品。如果用w[n]来存储各个物品的体积,那么k的取值为0,1,\dots,n-1,k号物品的体积是w[k],当k号物品不合适时,就需要尝试k+1号物品。

void knapsack(int w[], int T, int n) {//体积为T,总量为n
	LinkStack S = new LNode;
	InitStack(S);
	int k = 0;//已经试过的
	do {
		while (k < n && T>0) {
			if (T >= w[k]) {
				Push(S, k);
				T -= w[k];
			}
			k++;
		}
		if (T == 0) {
			Traceback(S);//回溯
		}
		if (!StackEmpty(S)) {//无论是运行到最后一条,还是已经找到解法,都要回溯
			Pop(S, k);
			T += w[k];
			k++;
		}
	} while (!StackEmpty(S) || k != n);
	DestroyStack(S);
}

新增了两条函数

输出函数TraceBack(S),即执行输出的函数

void Traceback(LinkStack& S) {
	ElemType k;
	printf("找到一组解法: ");
	for (int i = 0;; i++) {
		if (Pop(S, k)) {
			printf("%d ", k);
		}
		else {
			printf("\n");
			break;
		}
	}
}

还有一个判断栈是否为空的函数StackEmpt(S)

bool StackEmpty(LinkStack& S) {
	return (S == NULL);
}

正在扩充ing……

搜寻好题还会放在此贴下~ 

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值