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 ...
随机推荐
- MVC 初始 Log4net (一)
以前没有使用过Log4net 插件来记录日志文件,今天研究了一下,算是有点小眉目了,只是简单的使用一下:来写一篇博客自己记录一下,希望大神们多多包涵,小伙伴多多给提些建议,相互学习,我也是初始阶段,有 ...
- Linux下cron的使用
cron是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业.由于Cron 是Linux的内置服务,但它不自动起来,可以用以下的方法启动.关闭这个服务: /sbin/service c ...
- Windows Live Writer教程及代码高亮工具
十分感谢六仙庵对于Windows Live Writer的教程,方便了编辑与发布,教程地址如下: http://www.cnblogs.com/liuxianan/archive/2013/04/13 ...
- Angularjs 如何在 post 请求时去掉因 ng-repeat 产生的 $$hashkey?
序列化的时候用 angular.toJson 和 angular.fromJson ,不要用 Json.parse 和 JSON.stringify 就可以了.
- Ionic 安装部署
Ionic 安装部署 准备工作 下载安装Node.js, JDK,Apache Ant,Android SDK:编辑器用WebStorm node jdk ant 均需要加进 环境变量path中 An ...
- hdu 4005 The war
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005 In the war, the intelligence about the enemy is ...
- Connection reset by peer: socket write error 连数据库出现改错
1.网络原因 2.从池中获取连接后没有释放到池中导致的
- [百度空间] ld: add library file reference by path & file name
By default, -l option will search libraries with lib* prefix in speficied search paths. i.e. 1 ld -o ...
- Scrum敏捷软件开发之技术实践——测试驱动开发TDD
重复无聊的定义 测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法.它要求在编写某个功能的代码之前先编写测试代码,然后只编写 ...
- 彻底理解js中this的指向
首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...