Project Euler 103: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时的最优特殊和集,求其对应的集合数字串。
解题
题目坑了我好久
注意几点:
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 特殊的子集和:最优解的更多相关文章
- 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 ...
- 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 ...
- Python练习题 037:Project Euler 009:毕达哥拉斯三元组之乘积
本题来自 Project Euler 第9题:https://projecteuler.net/problem=9 # Project Euler: Problem 9: Special Pythag ...
- [project euler] program 4
上一次接触 project euler 还是2011年的事情,做了前三道题,后来被第四题卡住了,前面几题的代码也没有保留下来. 今天试着暴力破解了一下,代码如下: (我大概是第 172,719 个解出 ...
- 洛谷P1466 集合 Subset Sums
P1466 集合 Subset Sums 162通过 308提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目描述 对于从1到N (1 ...
- Python练习题 029:Project Euler 001:3和5的倍数
开始做 Project Euler 的练习题.网站上总共有565题,真是个大题库啊! # Project Euler, Problem 1: Multiples of 3 and 5 # If we ...
- Project Euler 9
题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...
- Codeforces348C - Subset Sums
Portal Description 给出长度为\(n(n\leq10^5)\)的序列\(\{a_n\}\)以及\(m(m\leq10^5)\)个下标集合\(\{S_m\}(\sum|S_i|\leq ...
- 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 ...
随机推荐
- 未能加载文件或程序集“System.Web.Razor”或它的某一个依赖项。文件或目录损坏且无法读取。
“/”应用程序中的服务器错误. 未能加载文件或程序集“System.Web.Razor”或它的某一个依赖项.文件或目录损坏且无法读取. (异常来自 HRESULT:0x80070570) 说明: 执行 ...
- 36.Altium Designer(Protel)网络连接方式Port和Net Label详解
1.图纸结构 图纸包括两种结构关系: 一种是层次式图纸,该连接关系是纵向的,也就是某一层次的图纸只能和相邻的上级或下级有关系:另一种是扁平式图纸,该连接关系是横向的,任何两张图纸之间都可以建 ...
- Java实现Internet地址获取
Java实现Internet地址获取 代码内容 输入域名输出IPV4地址 输入IP地址输出域名 支持命令行输入 支持交互式输入 代码实现 /* nslookup.java */ import java ...
- Labview实现单边带信号调制(SSB)[移相法]
Labview实现单边带信号调制(SSB)[移相法] 时域上的表达式为 调制器模型为 这个实验中需要相位偏移比较多,因为一共用了四个信号仿真器,一个是无偏移的调制信号,一个是偏移的调制信号,一个是无偏 ...
- 编译QT时出现lib/libQtGui.so: undefined reference to `ts_read_raw'的解决办法
lib/libQtGui.so: undefined reference to `ts_read_raw' /lib/libQtGui.so: undefined reference to `ts_o ...
- springboot快速搭建
环境 spring-boot-starter-parent 是一个特殊的starter,它提供了有用的Maven默认设置.同时,它也提供了一个 dependency-management 节点,这样对 ...
- 字符串流sstream[part3/使用字符串流进行安全的类型转换]
参考: http://blog.163.com/zhuandi_h/blog/static/180270288201291710222975/ http://www.cnblogs.com/games ...
- Android -- 获取汉字的首字母
转换 获取一个汉 ...
- RobotFramework-调用.py文件
RobotFramework-调用.py文件,直接运行: 注意:文件路径的\全部换成好了/
- 使用CSS时间打点的Loading效果的教程
基于box-shadow实现的打点效果 理论上,box-shadow可以实现任意的图形效果,自然我们可以利用box-shadow生成我们的点效果,然后通过animation控制不同时间点点的数目就可以 ...