/题目:
注:要求提交程序源代码和执行结果,编程语言不限。
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)=2f(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;
}