子集和问题(c语言实现)

5.1题目
算法实现题 5-1 子集和问题
★问题描述:子集和问题的一个实例为<S,t>。其中,S={X1,X2,…Xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得 Σx =c.
试设计一个解子集和问题的回溯法。
★算法设计:对于给定的正整数集合S={X1,X2,… Xn}和正整数c,计算S的一个集合S1,使得Σx=c。
★数据输入:由文件input.txt提供输入数据。文件第一行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中有n个正整数,表示集合S中的元素。
★结果输出:将子集和问题的解输出到文件output.txt。当问题无解时,输出“No Solution!”。
输入文件示例 输出文件示例
Input.txt output.txt
5 10 2 2 6
2 2 6 5 4

5.2分析
在我看来回溯算法就是找到问题的一个解,并不能找到问题的最优解,因此此类问题适合使用回溯算法,在回溯算法使用前应先画出一个大概的树状图,在使用回溯算法递归时定义局部静态变量以防止变量在递归时被刷新,或者定义全局变量也可,当余下数全选时加上当前数值大于常数c时即可继续加和,否则这条线路就没有了继续的必要,因为解必然不在此列。
5.3源代码

#include <iostream>
#include<stdio.h>//回溯算法
int huisu(int i, int* p, int* q, int n);
int c = 10;
int main()
{
	FILE* fpr, * fpw;
	int i = 0, max, z, n ;
	int b[100], a[100];
	fopen_s(&fpr, "input.txt", "r");
	fopen_s(&fpw, "output.txt", "w");
	fscanf_s(fpr, "%d", &n);
	fscanf_s(fpr, "%d", &c);
	for (i = 0; i < n; i++)
		fscanf_s(fpr, "%d", a + i);
	z = huisu(i = 0, b, a, n);
	if(z!=0)
	for (i = 0; i < z; i++)
		fprintf(fpw, "%d ", *(b + i));
	else
		fprintf(fpw, "No Solution!");
	fclose(fpr);
	fclose(fpw);
	return 0;
}
int huisu(int i, int* p, int* q, int n)
{
	static int max = 0, r = c, z = 0;//局部静态变量存储max,保证递归时不丢失数据
	int  right;
	if ((max == c) && (i <= n))
		return z;
	if(i > n)
		return 0;
	if (max + r >= c)//走左侧
	{
		r -= q[i];
		right = q[i];
		max += right;
		p[z++] = right;
		huisu(i + 1, p, q, n);//递归
	}
	else
		huisu(i + 1, p, q, n);
}

5.4运行结果
在这里插入图片描述
5.5总结
早上上课时刚刚讲过回溯算法就能在这里加以运用,巩固了所学知识,加深记忆并用以实践,其实回溯算法无非就是递归加判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chaoql

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值