您的位置:首页 > 其它

project euler 103

2015-12-26 01:28 225 查看
Special subset sums: optimum

Let S(A) represent the sum of elements in set A of size n. We shall call it a special sum set if for any two non-empty disjoint subsets, B and C, the following properties are true:

S(B) ≠ S(C); that is, sums of subsets cannot be equal.
If B contains more elements than C then S(B) > S(C).

If S(A) is minimised for a given n, we shall call it an optimum special sum set. The first five optimum special sum sets are given below.

n = 1: {1}

n = 2: {1, 2}

n = 3: {2, 3, 4}

n = 4: {3, 5, 6, 7}

n = 5: {6, 9, 11, 12, 13}

It seems that for a given optimum set, A = {a1, a2,
… , an}, the next optimum set is of the form B = {b, a1+b,
a2+b, … ,an+b}, where b is the “middle”
element on the previous row.

By applying this “rule” we would expect the optimum set for n = 6 to be A = {11, 17, 20, 22, 23, 24}, with S(A) = 117. However, this is not the optimum set, as we have merely applied an algorithm to provide a near optimum set. The optimum set for n = 6 is A
= {11, 18, 19, 20, 22, 25}, with S(A) = 115 and corresponding set string: 111819202225.

Given that A is an optimum special sum set for n = 7, find its set string.

NOTE: This problem is related to Problem
105 and Problem
106.

特殊的子集和:最优解

记S(A)是大小为n的集合A中所有元素的和。若任取A的任意两个非空且不相交的子集B和C都满足下列条件,我们称A是一个特殊的和集:

S(B) ≠ S(C);也就是说,任意子集的和不相同。
如果B中的元素比C多,则S(B) > S(C)。

对于给定的n,我们称使得S(A)最小的集合A为最优特殊和集。前5个最优特殊和集如下所示。

n = 1: {1}

n = 2: {1, 2}

n = 3: {2, 3, 4}

n = 4: {3, 5, 6, 7}

n = 5: {6, 9, 11, 12, 13}

似乎对于一个给定的最优特殊和集A = {a1, a2,
… , an},下一个最优特殊和集将是B = {b, a1+b, a2+b,
… ,an+b}的形式,其中b是集合A“正中间”的元素。

应用这条“规则”,我们猜测对于n = 6的最优特殊和集将是A = {11, 17, 20, 22, 23, 24},相应的S(A) = 117。然而,事实并非如此,我们的方法仅仅只能找出近似最优特殊和集。对于n = 6,最优特殊和集是A = {11, 18, 19, 20, 22, 25},相应的S(A) = 115,对应的集合数字串是:111819202225。

若集合A是n = 7时的最优特殊和集,求其对应的集合数字串。

注意:此题和第105题第106题有关。

package projecteuler;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import junit.framework.TestCase;

public class Prj103 extends TestCase {

List<int[]> resultList = new ArrayList<int[]>();

/**
* simple dfs;
* search start from n-1;
* k + (k + 1) > k + n -1
*/
public void testSpecialSubsetSumsOptimum() {
int[] arr = new int[7];
dfs(arr, 0, arr.length - 1, 50 );
System.out.println("size=" + resultList.size());

int sum = Integer.MAX_VALUE;
int minId = 0;

for( int i = 0 ; i < resultList.size() ; i ++){
int[] _val = resultList.get(i);
int val = sumArr(_val);
if( val < sum){
sum = val;
minId = i;
}
}

printArr(resultList.get(minId));
System.out.println("sum=" + sumArr(resultList.get(minId)) );

}

public void dfs(int[] arr, int id, int start, int end) {

if (id >= arr.length) {
if (checkOk(arr)) {
resultList.add(Arrays.copyOf(arr, arr.length));
printArr(arr);
}
return;
}

for (int i = start; i <= end; i++) {
if (id == 0) {

arr[id] = i;
dfs(arr, id + 1, start, end);

} else {

if (i <= arr[id - 1]) {
continue;
}

arr[id] = i;
dfs(arr, id + 1, start, end);
}

}

}

int sumArr(int arr[]) {
int sum = 0;
for (int val : arr) {
sum += val;
}
return sum;
}

private boolean checkOk(int[] arr) {

if (Arrays.equals(arr, new int[] { 11, 18, 19, 20, 22, 25 })) {
System.out.println();
}
assert (arr.length >= 5);
int n = arr.length;

int sumAsc = arr[0] + arr[1];
int sumDesc = arr[n - 1];
int count = 3;
int c = 2;
while (true) {
if (count > n) {
break;
}
if (sumAsc <= sumDesc) {
return false;
}
sumAsc += arr[c];
sumDesc += arr[n - c];
c++;
count += 2;

}

Set<Integer> set = new HashSet<Integer>();
int sum = 0;
for (int val : arr) {
set.add(val);
sum += val;
}
set.add(sum);

for (int p = 2; p <= n / 2; p++) {
Comb cb = new Comb(n, p);
List<int[]> cbs = cb.calculateComb();

for (int i = 0; i < cbs.size() - 1; i++) {
int[] _cb = cbs.get(i);

int sum1 = 0;
int sum2 = 0;
for (int j = 0; j < _cb.length; j++) {
if (_cb[j] == 1) {
sum1 += arr[j];
} else {
sum2 += arr[j];
}
}

if (set.contains(sum1)) {
return false;
}
set.add(sum1);

if (p == n / 2 && n % 2 == 0) {
continue;
}

if (set.contains(sum2)) {
return false;
}
set.add(sum2);
}

}

return true;
}

void printArr(int[] diff) {
for (int i = 0; i < diff.length; i++) {
System.out.print(diff[i] + "\t," );
}
System.out.println();
}

/**
* 组合
*
* @author suc
*
*/
public static class Comb {

private int n;
private int p;

public Comb(int n, int p) {
this.n = n;
this.p = p;
}

public List<int[]> calculateComb() {

assert (p < n && p > 0);

List<int[]> ret = new ArrayList<int[]>();

int[] arrs = new int
;
for (int i = 0; i < p; i++) {
arrs[i] = 1;
}

ret.add(Arrays.copyOf(arrs, arrs.length));

for (;;) {

boolean find = findNext(arrs);
ret.add(Arrays.copyOf(arrs, arrs.length));
if (!find) {
break;
}

}

return ret;

}

private boolean findNext(int[] arrs) {

int count = 0;
int find = -1;

for (int i = 0; i < arrs.length - 1; i++) {
if (arrs[i] == 1) {
count++;
}

if (arrs[i] == 1 && arrs[i + 1] == 0) {

int tmp = arrs[i + 1];
arrs[i + 1] = arrs[i];
arrs[i] = tmp;
find = i;
break;
}

}

count--;

for (int i = 0; i < find; i++) {
if (i < count) {
arrs[i] = 1;
} else {
arrs[i] = 0;
}
}

return !(find == -1);
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: