教你如何求一个集合的所有非空子集的方差和

/题目:
注:要求提交程序源代码和执行结果,编程语言不限。
1.对于一个大小为n的数集,求出该数集的每个"非空子集"的方差之和对10°+7取模的结果。
附件1说明:第一行一个正整数口表示集合大小,第二行几个整数表示集合中的元素。
/

/求集合的所有子集的算法(1):
对于任意集合A,元素个数为n(空集n=0),其所有子集的个数为2^n个
如集合A={a,b,c},其子集个数为8;对于任意一个元素,在每个子集中,
要么存在,要么不存在,对应关系是:
a->1或a->0
b->1或b->0
c->1或c->0
映射为子集:
(a,b,c)
(1,1,1)->(a,b,c)
(1,1,0)->(a,b )
(1,0,1)->(a, c)
(1,0,0)->(a )
(0,1,1)->( b,c)
(0,1,0)->( b )
(0,0,1)->( c)
(0,0,0)->@ (@表示空集)
算法(1):
观察以上规律,与计算机中数据存储方式相似,故可以通过一个整型数(int)与
集合映射000…000 ~ 111…111(0表示有,1表示无,反之亦可),通过该整型数
逐次增1可遍历获取所有的数,即获取集合的相应子集。
在这里提一下,使用这种方式映射集合,在进行集合运算时,相当简便,如
交运算对应按位与&,{a,b,c}交{a,b}得{a,b}<—>111&110==110
并运算对应按位或|,
差运算对应&~。
/

/求集合的所有子集的算法(1):
设函数f(n)=2^n (n>=0),有如下递推关系f(n)=2
f(n-1)=2*(2f(n-2))
由此可知,求集合子集的算法可以用递归的方式实现,对于每个元素用一个映射列表marks,标记其在子集中的有无
很显然,在集合元素个数少的情况下,算法(1)优于算法(2),因为只需通过加法运算,便能映射出子集,
而算法(2)要递归调用函数,速度稍慢。但算法(1)有一个严重缺陷,集合的个数不能大于在计算机中一个整型数的位数,
一般计算机中整型数的为32位。对于算法(2)就没这样限制。
/

/求 方差和 的算法:
求每个子集的均值和方差
然后求所有子集方差和
/

#include<iostream>
#include<vector>
#include<numeric>
#include<cmath>
#include<algorithm>
using namespace std;

double s = 0.0;

double average(vector<int>& subset)//计算均值
{
	double sum = accumulate(subset.begin(), subset.end(), 0.0);
	double mean = sum / subset.size();

	return mean;
}

double variance(vector<int>& subset, double mean)
{
	double accum = 0.0;
	std::for_each(subset.begin(), subset.end(), [&](const double d) {
		accum += pow(d - mean, 2);
		});
	if (accum == 0) return 0;
	else return accum/subset.size();
}

void print1(const vector<int>& a, int mark, int length)
{
	bool allZero = true;
	int limit = 1 << length;
	double mean = 0.0, accum = 0.0;
	vector<int>temp;
	cout << "子集:";
	for (int i = 0; i < length; ++i)
	{
		if (((1 << i) & mark) != 0) //mark第i+1位为1,表示取该元素
		{
			allZero = false;
			cout << a[i] << " ";
			temp.push_back(a[i]);
		}
	}

	if (allZero == true) 
	{ 
		cout << "空集"; 
		cout << "     均值:无";
		cout << "     方差:无";
	}
	else 
	{
		cout << "     均值:";
		mean = average(temp);
		cout << mean;

		cout << "     方差:";
		accum = variance(temp, mean);
		cout << accum;
	}
	
	s += accum;

	cout << endl;
}
void subset1(const vector<int>& a, int length)
{
	if (length > 31) return;

	int lowFlag = 0; //对应000...000
	int highFlag = (1 << length) - 1; //对应111...111

	for (int i = lowFlag; i <= highFlag; ++i)
	{
		print1(a, i, length);
	}
}

void print2(vector<int>& a, vector<bool>& marks, int length)
{
	double mean = 0.0, accum = 0.0;
	vector<int>temp;
	bool allFalse = true;

	cout << "子集:";
	for (int i = 0; i < length; ++i)
	{
		if (marks[i] == true)
		{
			allFalse = false;
			cout << a[i] << "  ";
			temp.push_back(a[i]);
		}
	}

	if (allFalse == true)
	{
		cout << "空集";
		cout << "     均值:无";
		cout << "     方差:无";
	}
	else
	{
		cout << "     均值:";
		mean = average(temp);
		cout << mean;

		cout << "     方差:";
		accum = variance(temp, mean);
		cout << accum;
	}

	s += accum;

	cout << endl;
}


void subset2(vector<int>& a, vector<bool>& marks, int m, int n, int length)
{
	if (m > n) 	print2(a, marks, length);
	else
	{
		marks[m] = true;
		subset2(a, marks, m + 1, n, length);
		marks[m] = false;
		subset2(a, marks, m + 1, n, length);
	}
}

int main()
{
	int n;
	vector<int>set;//set表示集合
	cin >> n;
	
	for (int i = 0, x; i < n; i++)
	{
		cin >> x;
		set.push_back(x);
	}
	if (n < 32) subset1(set, n);
	else
	{
		vector<bool> marks(n, 0);
		subset2(set, marks, 0, n - 1, n);
	}

	cout << "方差和 对10的9次方+7 取模 结果:";
	cout << (int)s % int(pow(10, 9) + 7) << endl;

	return 0;
}

集合的非空子集方差和

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值