实验1.1 递归练习——子集价值

实验1.1 递归练习——子集价值

题目描述

现有一个有 n n n个元素的序列 a = [ a 1 , a 2 , ⋯   , a n ] a=[a_1,a_2,\cdots, a_n] a=[a1,a2,,an],定义这个序列的价值为 ∑ i = 1 n i × a i \sum_{i=1}^{n}i\times a_i i=1ni×ai。空序列的价值为 0 0 0

先给你一个长度为 n n n的序列 a a a,求 a a a中所有子集价值的异或和,要求子集中元素的相对位置保持不变。

异或和: 位运算的一种。如果a、b两个值不相同,则异或结果为 1 1 1;如果a、b两个值相同,异或结果为 0 0 0

输入输出格式

输入

第一行一个整数 n n n

接下来一行有n个非负整数表示 a 1 , a 2 , ⋯   , a n a_1, a_2, \cdots, a_n a1,a2,,an

输出

一个整数表示所有子集的异或和

思路与探讨

递归算法:把一个大型复杂的问题,一次次通过递归调用而层层转化为一个与原问题相似的规模较小的问题来求解,基本思想是将大问题一步步化为小问题。

小破站讲解视频分享

思路:子集价值核心思路即用递归求出集合的子集,并由所求子集求出价值以及异或和。在求子集的过程中,关键思路即每一个元素都有取和不取两种选择,因而核心代码为:

tag[start] = 1;
subArray(array,start + 1,n);//该元素选入,向下递归 
tag[start] = 0;
subArray(array,start + 1,n);//该元素不选,向下递归 

关注:应当另开一个 bool 数组,相当于给每个元素打上标签,用 1 或 0 分别表示选入或不选入,在进行向下递归,再判断选入不选入,从而给出所有可能子集。


若已看懂思路,试着自己写~


实现代码

#include<iostream>
using namespace std;
bool tag[100] = {};//打标签 
int subarray[100] = {};//用于存生成的子集 
int value = 0;//异或和初始化 

int subArray(int *array,int start,int n)
{
	int sum = 0,num = 0;
	if(start < n)
    {//可以平均地把每个tag的元素都给上0或1两种状态,每个元素都有取和不取两种选择 
		tag[start] = 1;
		subArray(array,start + 1,n);//该元素选入,向下递归 
		tag[start] = 0;
		subArray(array,start + 1,n);//该元素不选,向下递归 
	}
	if(start == n)
    {
		for(int i = 0;i < n;i++)
		{
			if(tag[i])
			{
				subarray[num] = array[i];//生成子集存入 
				num++;
			}
		}
		for(int j = 0;j < num;j++)
		{
			sum += subarray[j] * (j+1);//子集价值计算 
		}
		value ^= sum;//子集异或和计算	
	}
	return value;
}

int main()
{
	int n;
	int array[20];
	cin >> n;
	for(int i = 0;i < n;i++)
		cin >> array[i];
	cout << subArray(array,0,n) << endl; 
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

啦啦右一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值