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:

  1. S(B) ≠ S(C); that is, sums of subsets cannot be equal.
  2. 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是一个特殊的和集:

  1. S(B) ≠ S(C);也就是说,任意子集的和不相同。
  2. 如果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题有关。

解题

题目坑了我好久

注意几点:

1.上面说的A的子集 B 和C ,B C 只是其中的任意两个子集,不是 B 和C的并等于A

2.A的任意子集都要满足上面两个条件,同时注意:B和C不能有交集

3.题目要求的是对于n的最优特殊和集,通过上面调整的是最近特殊和集,最优特殊和集在同样的n的情况下,其集合的和是最小的

4.7个数不相同,还是升序的

暴力解题:

1.在{19,30,37,38,39,41,44} 7个点附近寻找

2.求出所有的子集

3.对不相交的子集,利用题目给的两个条件进行求解

4.和最小的集合就是答案

下面程序参考了Mathblog,但是其是先求出每个子集的和,对于子集交集的没有看到,我改成求出所有的子集,再暴力找满足条件的值。

下面程序中在组合成初始集合A,最不好的方法也不是严格的在{19,30,37,38,39,41,44} 附近寻找的。同时,是用ArrayList当作集合用表示不是很好

JAVA

package Level4;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet; public class PE0103{ // 对{20, 31, 38, 39, 40, 42, 45} //255 中的每个点+-3暴力求出所有的可能
// {19,30,37,38,39,41,44} //
public static void run(){
int a[] = {19,30,37,38,39,41,44};
int min = -3;
int max = 3;
int c1[] = {19 ,30, 37, 38, 39, 41,44};
int c2[] = {19 ,31, 38, 39, 40, 42, 45};
int c3[] = {20, 31, 38, 39, 40, 42, 45};
int c4[] = {6, 9, 11, 12, 13};
int c5[] = {11, 18, 19, 20, 22, 25};
System.out.println(isOptimum(c1));
System.out.println(isOptimum(c2));
System.out.println(isOptimum(c3));
System.out.println(isOptimum(c4));
System.out.println(isOptimum(c5));
for(int a0 = a[0] ;a0<=a[0]+ max ;a0++){
for(int a1 = a0+1;a1<= a[1]+max ;a1++){
for(int a2 = a1+1;a2<=a[2]+max ;a2++){
for(int a3 = a2+1;a3<=a[3]+max ;a3++){
for(int a4 = a3+1;a4<=a[4]+max ;a4++){
for(int a5 = a4+1;a5<=a[5]+max ;a5++){
for(int a6 = a5+1;a6<=a[6]+max ;a6++){
int[] b= {a0,a1,a2,a3,a4,a5,a6};
if(isOptimum(b)){
String str = printArrStr(b); str = str + "\t SUM:"+sum(b);
System.out.println(str);
}
}
}
}
}
}
}
} }
public static String printArrStr(int[] a){
String str ="";
for(int i=0;i<a.length;i++){
str +=" "+a[i];
} return str; }
public static String printArrStr(ArrayList<Integer> list){
String str ="";
for(int i=0;i<list.size();i++){
str += " "+list.get(i);
}
return str;
}
// 验证 是否是最优子集
// 子集 一个集合可能有多个子集,而下面的程序只是看成两个自己的情况,两个子集的并集等于原来集合,照成程序有问题
public static boolean isOptimum(int[] a){
// 所有的子集
ArrayList<ArrayList<Integer>> sets = MakeSubsets(a);
int size = sets.size();
// System.out.println(size);
for(int i=0;i<size;i++){
ArrayList<Integer> set1 = sets.get(i);
for(int j=i+1;j<size;j++){
ArrayList<Integer> set2 = sets.get(j);
if(!isDisjoint(set1,set2)){
int sum1 = sum(set1);
int sum2 = sum(set2);
if(sum1 == sum2)
return false;
if(set1.size() > set2.size() && sum1 <=sum2)
return false;
if(set1.size() < set2.size() && sum1 >= sum2)
return false;
}
}
}
return true;
} // 求集合内元素的和
public static int sum(ArrayList<Integer> set){
int sum = 0;
for(int i=0;i< set.size();i++){
sum += set.get(i);
}
return sum;
}
public static int sum(int [] a){
int sum = 0;
for(int i=0;i< a.length;i++){
sum += a[i];
}
return sum;
}
// 两个子集元素是否相交 true 相交 false 不相交
public static boolean isDisjoint(ArrayList<Integer> set1,ArrayList<Integer> set2){
int size1 = set1.size();
int size2 = set2.size();
ArrayList<Integer> set = new ArrayList<Integer>();
for(int i=0;i<size1;i++){
int element = set1.get(i);
if(set.contains(element))
return true;
else
set.add(element);
}
for(int i=0;i<size2;i++){
int element = set2.get(i);
if(set.contains(element))
return true;
else
set.add(element);
}
set.clear();
return false; } // 求出所有子集的和
public static int[] MakeSubsetSums(int[] a){
int b[] = new int[(int)Math.pow(2, a.length) ];
for(int i=1;i<b.length;i++){
b[i] = MakeSubsetSum(a,i);
}
return b;
}
// 求出所有的子集
public static ArrayList<ArrayList<Integer>> MakeSubsets(int a[]){
ArrayList<ArrayList<Integer>> sets = new ArrayList<ArrayList<Integer>>();
for(int i=1;i<= (int) Math.pow(2,a.length);i++){
ArrayList<Integer> set = MakeSubset(a,i);
sets.add(set);
String s = printArrStr(set);
// System.out.println(s);
}
return sets; }
// 求出子集
public static ArrayList<Integer> MakeSubset(int[] a,int m){
ArrayList<Integer> set = new ArrayList<Integer>();
for(int i=0;i<a.length ;i++){
if( m>0 &&(m&1)==1){
set.add(a[i]);
}
m =m>>1;
}
return set;
}
// 求子集的和
// 利用 和 1 进行与运算 并移位
// 001001 相当于根据 1 所在的位置取 第 2 第 5的位置对应的数
// &000001
//----------
// 1 取出该位置对应的数
// 下面右移一位后
// 000100
// 下面同理了
public static int MakeSubsetSum(int[] a,int m){
int sum = 0;
for(int i=0;i< a.length;i++){
if( m>0 && (m&1) == 1)
sum +=a[i];
m >>=1;
}
return sum;
}
public static void main(String[] args){
long t0 = System.currentTimeMillis();
run();
long t1 = System.currentTimeMillis();
long t = t1 - t0;
System.out.println("running time="+t/1000+"s"+t%1000+"ms");
}
}

结果

 20 31 38 39 40 42 45     SUM:255
20 32 39 40 41 43 46 SUM:261
20 33 40 41 42 44 47 SUM:267
21 32 39 40 41 43 46 SUM:262
21 33 40 41 42 44 47 SUM:268
22 33 40 41 42 44 47 SUM:269
running time=164s431ms

第一个就是答案,可以看出,直接根据第6个最优特征子集也可以推出下一个最优特殊子集

Python 质量也是好差

# coding=gbk

import time as time
import re
import math
import numpy as np
def run():
a= [19,30,37,38,39,41,44]
f = lambda x:x+1
a0 = map(f,range(16,22))
a1 = map(f,range(27,34))
a2 = map(f,range(34,41))
a3 = map(f,range(35,42))
a4 = map(f,range(36,43))
a5 = map(f,range(37,44))
a6 = map(f,range(41,48))
for a in a0:
for b in a1:
for c in a2:
for d in a3:
for e in a4:
for f in a5:
for g in a6:
if a<b and b<c and c<d and d<e and e<f and f<g:
A = [a,b,c,d,e,f,g]
if isOptimum(A):
print A,'\t',sum(A) # [20, 31, 38, 39, 40, 42, 45] 255
# [20, 32, 39, 40, 41, 43, 46] 261
# [20, 33, 40, 41, 42, 44, 47] 267
# [20, 34, 37, 39, 40, 41, 48] 259
# [21, 32, 39, 40, 41, 43, 46] 262
# [21, 33, 40, 41, 42, 44, 47] 268
# [22, 33, 40, 41, 42, 44, 47] 269
# running time= 52.3980000019 s
def isOptimum(a):
sets = subSets(a)
# print len(sets)
for i in range(len(sets)):
for j in range(i+1,len(sets)):
s1 = sets[i]
s2 = sets[j]
if isDisjoint(s1,s2) == False:
sum1 = sum(s1)
sum2 = sum(s2)
len1 = len(s1)
len2 = len(s2)
# print s1,'\t',s2
if sum1 == sum2:return False
if len1>len2 and sum1<=sum2:return False
if len1<len2 and sum1>=sum2:return False
return True
def isDisjoint(b,c):
for bi in b:
if bi in c:
return True
return False def subSets(a):
l = 2**len(a)
sets = []
for i in range(1,l):
s = subSet(a,i)
sets.append(s)
return sets
# 求一个子集
def subSet(a,m):
s = []
for i in range(len(a)):
if (m&1)==1:
s.append(a[i])
m =m>>1
return s t0 = time.time()
run()
t1 = time.time()
print "running time=",(t1-t0),"s"

Project Euler 103:Special subset sums: optimum 特殊的子集和:最优解的更多相关文章

  1. Project Euler 106:Special subset sums: meta-testing 特殊的子集和:元检验

    Special subset sums: meta-testing Let S(A) represent the sum of elements in set A of size n. We shal ...

  2. Project Euler P105:Special subset sums: testing 特殊的子集和 检验

    Special subset sums: testing Let S(A) represent the sum of elements in set A of size n. We shall cal ...

  3. Python练习题 037:Project Euler 009:毕达哥拉斯三元组之乘积

    本题来自 Project Euler 第9题:https://projecteuler.net/problem=9 # Project Euler: Problem 9: Special Pythag ...

  4. [project euler] program 4

    上一次接触 project euler 还是2011年的事情,做了前三道题,后来被第四题卡住了,前面几题的代码也没有保留下来. 今天试着暴力破解了一下,代码如下: (我大概是第 172,719 个解出 ...

  5. 洛谷P1466 集合 Subset Sums

    P1466 集合 Subset Sums 162通过 308提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 对于从1到N (1 ...

  6. Python练习题 029:Project Euler 001:3和5的倍数

    开始做 Project Euler 的练习题.网站上总共有565题,真是个大题库啊! # Project Euler, Problem 1: Multiples of 3 and 5 # If we ...

  7. Project Euler 9

    题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...

  8. Codeforces348C - Subset Sums

    Portal Description 给出长度为\(n(n\leq10^5)\)的序列\(\{a_n\}\)以及\(m(m\leq10^5)\)个下标集合\(\{S_m\}(\sum|S_i|\leq ...

  9. Project Euler 44: Find the smallest pair of pentagonal numbers whose sum and difference is pentagonal.

    In Problem 42 we dealt with triangular problems, in Problem 44 of Project Euler we deal with pentago ...

随机推荐

  1. 从零开始学ios开发(二):Hello World!来啦!

    今天看了书的第二章,主要介绍了一下Xcode的使用方法和一些必要的说明,最后做了一个“Hello World!”的小程序,其实就是在屏幕上用一个Label显示“Hello World!”,一行代码都没 ...

  2. web安全之token

    Token,就是令牌,最大的特点就是随机性,不可预测.一般黑客或软件无法猜测出来. 那么,Token有什么作用?又是什么原理呢? Token一般用在两个地方: 1)防止表单重复提交. 2)anti c ...

  3. qt QSS文件伪状态

    表 1. 伪状态列表伪状态    描述:checked    button部件被选中:disabled    部件被禁用:enabled    部件被启用:focus    部件获得焦点:hover  ...

  4. 理解JavaScript中的事件路由冒泡过程及委托代理机制

    当我用纯CSS实现这个以后.我开始用JavaScript和样式类来完善功能. 然后,我有一些想法,我想使用Delegated Events (事件委托)但是我不想有任何依赖,插入任何库,包括jQuer ...

  5. iOS开发HTTPS实现之信任SSL证书和自签名证书

    iOS开发HTTPS实现之信任SSL证书和自签名证书 转自:http://www.jianshu.com/p/6b9c8bd5005a/comments/5539345 (收录一下供自己学习用的) 字 ...

  6. < java.util >-- Iterator接口

    每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式.为了便于操作所有的容器,取出元素.将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口. 也就说,只要通过该 ...

  7. Liunx0000(初步认识)

    都要放假了,学习一下吧,毕竟还有课设,虽然我真的懒得看Linux,不想接触这破玩意!各应人的东西! 一.发展趋势 1\无操作系统阶段20s60 2\简单操作系统阶段 3\试试操作系统阶段 4\面向In ...

  8. Team Homework #3 软件工程在北航——IloveSE

    任务要求: 采访以前上过北航  (计算机系/软件学院) 软件工程课的同学.现在上研/工作的也可以. 采访问题如下:* 平均每周花在这门课上的时间 (包括上课/作业/上机)    * 平均写的代码总行数 ...

  9. 如何不通过系统升级来安装window10正式版?(特别针对Xp用户)

    今天是个特殊的日子7/29,相信大家都等了很久了吧,win10正式版终于上线,一些不懂电脑的人只会通过360和腾讯管家等来升级到win10(XP用户除外),而对于大多数像我这样对系统比较热衷的人,我相 ...

  10. android 通过工具抓包

    工具: 1.tcpdump :http://www.strazzere.com/android/tcpdump 2.wireshark:http://pan.baidu.com/s/1geooiav ...