1. 程式人生 > >全組合 網易筆試 數字遊戲

全組合 網易筆試 數字遊戲

題目描述:

小易邀請你玩一個數字遊戲,小易給你一系列的整數。你們倆使用這些整數玩遊戲。每次小易會任意說一個數字出來,然後你需要從這一系列數字中選取一部分出來讓它們的和等於小易所說的數字。 例如: 如果{2,1,2,7}是你有的一系列數,小易說的數字是11.你可以得到方案2+2+7 = 11.如果頑皮的小易想坑你,他說的數字是6,那麼你沒有辦法拼湊出和為6 現在小易給你n個數,讓你找出無法從n個數中選取部分求和的數字中的最小數(從1開始)。

思路: 

(2) 對數論不瞭解,可以利用全排列來做。每個數字都有 {被使用,不使用} 兩種狀態,分別用 1 和 0 表示,恰恰對應計算機底層數字的二進位制表示,如:給定陣列 int a[3] = {1, 2, 3}

      0 0 0 : 表示不使用任何數

      0 0 1:表示使用第三個數,即3

      0 1 0:表示使用第二個數,即2

      0 1 1:表示使用第二個和第三個數,即 2 和 3

   ......

      1 1 1:表示使用第1,2,3個數

因此,通過遍歷 i = 1 到 2^n (n 為陣列長度)就可以窮舉所有的可能性。程式碼如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<string>
#include<set>
#include<queue>
using namespace std;
inline long long max(long long a, long long b){
	return (a > b) ? a : b;
}
inline long long min(long long a, long long b){
	return (a > b) ? b : a;
}
int n, a[22];
int maxn = 1000000000;
bool visited[2000002] = { false };


int main(int argc, char * argv[])
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);

	set<int> unique_nums;
	/**************** 計算機底層二進位制編碼 *****************/
	// 利用計算機內部天然的0/1二進位制編碼,得出 2^n 的全部方案:
	// Cn(1) + Cn(2) + Cn(3) ... + Cn(n)
	for (int num = 1; num <= (int)pow(2.0, 1.0*n); num++){
		int sum = 0;
		// 依次檢查 num 的第1個bit,第二個bit,..., 第n個bit
		for (int i = 1; i <= n; i++){
			int bit_pattern = 1 << (i - 1);
			int one_or_zero = num & bit_pattern;
			if (one_or_zero != 0)
				sum += a[i];
			visited[sum] = true;
		}
	}

	// 找到最小的
	for (int i = 1; i <= 2000000;i++)
	if (! visited[i] )
	{
		cout << i << endl;
		break;
	}
	return 0;
}