user-0 提问: 烧脑奇怪数-救救孩子

回复:
user: user-1
content: 上面已经有人用回溯法求解了子集，但是如果子集里面个数不是很多的话，是可以暴力用二进制来表示子集的。  [子集生成 递归回溯](https://blog.csdn.net/Africa_South/article/details/102612501) long long 限制子集个数在63以内  #include<iostream> #include<string> #include<cstring> #include<vector> #include<algorithm> using namespace std;  typedef long long LL; int factor[1010]; // 因子 int sum, cnt; // 因子的和，因子的个数 int subset; // 子集和,可以用sum代替 bool isYingshu(int num) { 	// 拆分一个数num，然后因子存入factor[]，并返回是不是盈数 	cnt = 0, sum = 0; 	factor[cnt++] = 1; sum += 1; // 1 肯定是因子 	for (int i = 2; i*i <= num; i++) { 		if (num % i == 0) { 			factor[cnt++] = i; sum += i; 			factor[cnt++] = num / i; sum += (num / i); 			if (i*i == num) { // 多算了一个 				cnt--; sum -= i; 			} 		} 	} 	if (sum <= num) return false; 	else return true; }  bool isStrange(int num) { 	// 返回是不是奇怪数 	if (!isYingshu(num)) return false; 	LL len = ((LL)1 << cnt); // 总共的子集情况 	for (LL i = 0; i < len; i++) { 		subset = 0; 		for (LL j = 0; j < cnt; j++) { 			if (i & ((LL)1 << j)) subset += factor[j]; 		} 		if (subset == num) return false; 	} 	return true; }  int main() { 	for (int i = 70; i <= 1000; i++) { 		if (isStrange(i)) { 			printf("该数%d，因子个数%d\n", i,cnt); 		} 	} 	return 0; }

user: user-2
content: #include <iostream> #include<stdio.h>  #include<stdlib.h> #include<math.h> #define  MAX  50 int back(int i, int s, int n); int static t; int i, j, n, k, sum=0, a[MAX], num; int flag = 1; int b[MAX] = { 0 };  //初始化数组b,给定数组a中的元素一个状态，类似排列组合  int main() { for (n =4; n <= 4; n++) { int i = 0,  num = 0; for (j = 2; j <= n - 1; j++) //找 n的所有因子  { if (n % j == 0) { a[i] = j;    //将n的因子存在数组a[1000]中  sum = sum + j;// 计算所有因子的和  i++;     //数组的序号+1  num++; //计算数组的大小，n的所有因子数  } } if(sum!=0）{} sum = sum + 1;  //1也是n的因子  a[num] = 1;  //把1赋给数组a[1000]  if (sum > n)  //判断n是否为赢数  { t = num + 1;    back(1, t, n);//把n的因子数赋给t  if (flag)//第1个元素开始 ，求n所有因子的子集的和并与sum比较 printf("%d是奇怪数", n); break;//找到第一个奇怪数后停止循环   } }   return 0; }    int back(int i, int s, int n) {  int k, Sum = 0; if (i > s)//判断a中的元素的状态是否都已确定  { for (k = 1; k <= s; k++)// 对a中的元素 进行排列组合  {  if (b[k])    //判断第K个元素的状态 { if (a[k] != 0) {  Sum += a[k];  } } } if (n == Sum) flag = 0;   return flag;//如果满足这个条件，就不用执行后面为a中的元素赋予一种状态的操作 }  { b[i] = 1;                //对a中元素的状态进行排列组合  back(i + 1, t, n); b[i] = 0; back(i + 1, t, n); return flag; } }

user: user-3
content: 这个好高深啊，弄不懂

user: user-4
content: 奇怪数为这样一个整数，①：除了自身以外所有因子之和大于这个数本身（首先必须是盈数）；②：除了自身以外所有因子的集合，没有任何一个子集中所有数的和等于这个数本身，例如70就是一个奇怪数，求1000以内的第二个奇怪数  好难呀

user: user-5
content: 10000以内7个数： 70 836 4030 5830 7192 7912 9272

user: user-6
content: 数学就是那么深奥真正有用 的地方很少。我们要学会有的放矢的学习

user: user-7
content: 兄弟 ，这行代码是你自己写。

user: user-8
content: 除了暴力外筛法+分解定理也可做，打一张1000内的表，再维护2张不符合两个条件的表分别筛一下

user: user-9
content: 什么意思？没用看懂哈哈

user: user-0
content: 打错了不好意思正确答案836

user: user-0
content: 答案不正确，正确答案是839

user: user-10
content: 这真的能运行出正确结果吗

user: user-0
content: 引用 36 楼 user-11的回复:memset初始化数组为0。 刚试了一下。这句代码是多余的。可以删掉。  我习惯清零了，所以就写了。 谢谢大佬，后面用回溯法求子集的还是不懂，我再仔细看看，非常感谢您

user: user-0
content: 兄弟这程序运行结果不对

user: user-11
content: memset初始化数组为0。 刚试了一下。这句代码是多余的。可以删掉。  我习惯清零了，所以就写了。

user: user-0
content: 引用 32 楼 user-11的回复:好了，改对了。  // user-11 // 2019年10月31日10:10:03 #include <stdio.h> #include <math.h> #include <string.h>  #define TRUE 1 #define FALSE 0 #define MAX_NUM 1000  int strangeNumber(int);// 判断是否是奇怪数  int sum;// 因子的和 int factor[MAX_NUM];// 保存因子 int factorNum;// 因子个数 int abundantNumber(int);// 判断是否是盈数  int back(int, int);// 回溯判断是否有子集的和是num  int main(void) { 	for (int i = 71; i <= 1000; ++i) { 		if (TRUE == strangeNumber(i)) { 			printf("%d\n", i); 			break; 		} 	} 	return 0; }  int strangeNumber(int num) { 	if (FALSE == abundantNumber(num)) { 		return FALSE;// 不是盈数，即不是奇怪数 	} 	if (FALSE == back(0, num)) { 		return FALSE;// 存在子集的和为num，即不是奇怪数 	} 	return TRUE; }  int abundantNumber(int num) { 	// 初始化 	memset(factor, 0, sizeof(factor)); 	factorNum = 0; 	factor[factorNum++] = 1;// 1肯定是因子 	sum = 1; 	int max = (int)sqrt(num); 	// 循环找到num的所有因子 	for (int i = 2; i <= max; ++i) { 		if (0 == num % i) { 			factor[factorNum++] = i; 			factor[factorNum++] = num / i; 			sum += i + num / i; 		} 	} 	// num是开方数，那么循环里面max加了两遍，要减掉多余的 	if (max * max == num) { 		--factorNum; 		sum -= max; 	} 	return sum <= num ? FALSE : TRUE; }  int back(int index, int left) { 	if (index >= factorNum) { 		return 0 == left ? FALSE : TRUE; 	} 	if (FALSE == back(index + 1, left)) {// 不选择第index个数 		return FALSE; 	} 	// 选择第index个数，剩余的减去当前数 	if (FALSE == back(index + 1, left - factor[index])) { 		return FALSE; 	} 	return TRUE; }   但是menset是干什么的函数呢

user: user-0
content: 还有这这能运行出来不😂😂我急用

user: user-0
content: 兄弟，你这是用啥写的，粘贴到c＋＋上一篇红色

user: user-0
content: 谢谢大哥，小女子无以为报，只能表达对您的景仰与感谢

user: user-11
content: 我发现搜不到这个题目的博客。所以整理成博客了，不迷路，哈哈哈哈：https://blog.csdn.net/pfdvnah/article/details/102832648