子集和问题(C语言)--回溯法

子集和问题

题目描述
给定一个正整数集合X={x1,x2,…,xn}和一个正整数c,设计回溯算法,求集合X的一个子集Y,使得Y中元素之和等于c。

解题思路
类似于全排列的思想,尝试所有结果,如果不符合则回溯

具体代码实现

#include <stdio.h>
#include <stdlib.h>
int flag=0,sum=0;
int *s, *x, n,c;
 
 //向文件写入一个数字 
void fileWrite(int i){

	FILE *fp;
	fp = fopen("i:\\算法\\回溯法\\output.txt", "a");
	
	if (fp == NULL) {			//若打开文件失败则退出
        printf("不能打开文件!\n");
        return ;
    }
	
	if(i == 32767){							//如果一种解法读入完毕,则换行 
		fprintf(fp,"\n"); 
	}
	else if(i<0){							//如果输入小于0则代表第几种解法 
		fprintf(fp,"第%d种解法:",-i); 		
	}else{
		fprintf(fp,"%d ",i); 
	}
	
	fclose(fp);	
}
 
 //从文件读取数据 
void fileRead(){
	FILE *fp;
	fp = fopen("i:\\算法\\回溯法\\input.txt", "r");
	if (fp == NULL) {			//若打开文件失败则退出
        printf("不能打开文件!\n");
        return ;
    }
 	//从文件中读入S的大小n和子集和的目标值c 
    fscanf(fp,"%d",&n);
    fscanf(fp,"%d",&c);
		
	s=(int *)malloc(sizeof(int)*n);
	x=(int *)malloc(sizeof(int)*n);
	
	//从文件中读取集合S中的n正整数元素
	for(int i=0;i<n;i++){
		fscanf(fp,"%d",&s[i]);
		x[i]=0;
	}
	
	fclose(fp);	
} 
 
void backtrack(int t){
	int i;
	if(t==n)
	{
		if(sum==c)
		{
			flag+=1;
			fileWrite(-flag);
			for(i=0;i<n;i++){
				if(x[i]){
					fileWrite(s[i]);
				}
			}
				
					
			fileWrite(32767);
			return;
		}
	}
	else
	{
		sum+=s[t];
		x[t]=1;
		backtrack(t+1);
		x[t]=0;
		sum-=s[t];
		backtrack(t+1);	
	}
}

int main(){

	fileRead(); 

	backtrack(0);
	
	if(flag > 0){
		printf("已将结果存入文件\n");
	}
	else{
		printf("No Solution!\n");
	} 
	
	return 0;
}
  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
子集问题是一个经典的组合优化问题,可以使用回溯法(backtracking)进行解。具体的思路是: 1. 定义一个数组或者集合,存储所有可选的数值。 2. 定义一个数组或者集合,存储当前已选的数值。 3. 定义一个变量,记录当前已选数值的和。 4. 从第一个数开始,遍历可选数值,对于每个可选数值,判断是否可以加入已选数值中。如果可以,则加入已选数值中,更新当前和,并且递归调用解决剩余问题;如果不可以,则不加入已选数值中,继续遍历下一个可选数值。 5. 当已选数值的和等于目标值时,输出当前已选数值,结束递归。 6. 当所有可选数值都遍历完毕,仍未找到解,则回溯到上一个节点,继续遍历下一个可选数值。 下面是 C 语言实现的示例代码: ```c #include <stdio.h> #define MAX_NUM 100 int nums[MAX_NUM]; int selected[MAX_NUM]; int sum, target; int n; void subset_sum(int k) { if (sum == target) { printf("Subset found: "); for (int i = 0; i < n; i++) { if (selected[i]) { printf("%d ", nums[i]); } } printf("\n"); return; } if (k == n || sum > target) { return; } selected[k] = 1; sum += nums[k]; subset_sum(k + 1); sum -= nums[k]; selected[k] = 0; subset_sum(k + 1); } int main() { printf("Enter the number of elements: "); scanf("%d", &n); printf("Enter the elements: "); for (int i = 0; i < n; i++) { scanf("%d", &nums[i]); } printf("Enter the target sum: "); scanf("%d", &target); subset_sum(0); return 0; } ``` 在实际应用中,为了避免重复计算,可以使用记忆化搜索或者动态规划进行优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值