Hairpin structure easy algorithm - python

I have a structure with letters A, Z, F, G.
A have a pair with Z, and F with G.
I have for example AAAFFZZGGFFGGAAAAZZZZ. And I need to "curve" structure and that fold will make a pairs
A A A F F Z Z G G F F -
* * * * * * |
Z Z Z Z A A A A G G -
6 pairs in upper example.
But we can create structure like this:
A A A F F Z Z G G -
* * * |
Z Z Z Z A A A A G G F F -
And head is a fragment of structure where pairs cannot exists. For example head 2:
rozmiar. Na przykład head = 2:
F F
A A A F F Z Z G G / \
* * * * |
Z Z Z Z A A A A \ /
G G
I don't know how to find maximal number of pairs that can be created in this structure

To make the matching go faster you can prepare a second string (R) with the letters flipped to their corresponding values. This will allow direct comparisons of paired positions instead of going through an indirection n^2 times:
S = "AAAFFZZGGFFGGAAAAZZZZ"
match = str.maketrans("AZFG","ZAGF")
R = S.translate(match) # flipped matching letters
mid = len(S)//2
maxCount,maxPos = 0,0
for d in range(mid+1): # moving away from middle
for p in {mid+d,mid-d}: # right them left
pairs = sum(a==b for a,b in zip(S[p-1::-1],R[p:])) # match fold
if pairs>maxCount:
maxCount,maxPos = pairs,p # track best so far and fold position
if p <= maxCount: break # stop when impossible to improve
print(maxCount) # 6 matches
print(maxPos) # folding at 11
print(S[:maxPos].rjust(len(S))) # AAAFFZZGGFF
print(S[maxPos:][::-1].rjust(len(S))) # ZZZZAAAAGG
# ** ** **

You could start with testing the folding point in the center, and then fan out (in zig-zag manner) putting the folding point further from the center.
Then for a given folding point, count the allowed pairs. You can use slicing to create the two strips, one in reversed order, and then zip those to get the pairs.
The outer iteration (determining the folding point) can stop when the size of the shortest strip is shorter than the size of the best answer found so far.
Here is a solution, which also returns the actual fold, so it can be printed for verification:
def best_fold(chain):
allowed = set(("AZ","ZA","FG","GF"))
revchain = chain[::-1]
maxnumpairs = 0
fold = chain # This represents "no solution"
n = len(chain)
head = n // 2
for diff in range(n):
head += diff if diff % 2 else -diff
if head - 2 < maxnumpairs or n - head - 2 < maxnumpairs:
break
numpairs = sum(a+b in allowed
for a, b in zip(revchain[-head+2:], chain[head+2:])
)
if numpairs > maxnumpairs:
maxnumpairs = numpairs
fold = chain[:head].rjust(n) + "\n" + revchain[:-head].rjust(n)
return maxnumpairs, fold
Here is how to run it on the example string:
numpairs, fold = best_fold("AAAFFZZGGFFGGAAAAZZZZ")
print(numpairs) # 5
print(fold) # AAAFFZZGGF
# ZZZZAAAAGGF

I would first start with a suitable data type to implement your creasable string. Now first things first, as you mention in your comment we can use list of characters which is better than a string. Then perhaps a tuple of arrays like [[Char],[Char]] would be sufficient.
Also creasing from left or right shouldn't matter so for simplicity we start with;
[ ["A","A","F","F","Z","Z","G","G","F","F","G","G","A","A","A","A","Z","Z","Z","Z"]
, ["A"]
]
then in every step;
Then in every step we can map our list of characters into a a tuple of creases like
chars.map((_,i,a) => [a.slice(i+1),a.slice(0,i+1).reverse()]
Compare and count for pairs.
In order to make an efficient comparison of corresponding items being a valid pair, a simple look up table as below can be used
{ "A": "Z"
, "Z": "A"
, "G": "F"
, "F": "G"
}
Finally we can filter the longest one(s)
An implementation of creases could be like;
function pairs(cs){
var lut = { "A": "Z"
, "Z": "A"
, "G": "F"
, "F": "G"
};
return cs.map(function(_,i,a){
var crs = [a.slice(i+1),a.slice(0,i+1).reverse()]; // console.log(crs) to see all creases)
return crs[0].reduce( (ps,c,j) => lut[c] === crs[1][j] ? ( ps.res.push([c,crs[1][j],j])
, ps.crs ??= crs.concat(i+1)
, ps
)
: ps
, { res: []
, crs: null
}
);
})
.reduce( (r,d) => r.length ? r[r.length-1].res.length > d.res.length ? r :
r[r.length-1].res.length < d.res.length ? [d] : r.concat(d)
: [d]
, []
);
}
var chars = ["A","A","A","F","F","Z","Z","G","G","F","F","G","G","A","A","A","A","Z","Z","Z","Z"],
result = pairs(chars);
console.log(result);
.as-console-wrapper{
max-height: 100% !important;
}
Now this is a straightforward algorithm and possibly not the most efficient one. It can be made more faster by using complex modular arithmetic on testing pairs without using any additional arrays however i believe it would be an overkill and very hard to explain.

Related

How can I implement this point in polygon code in Python?

So, for my Computer Graphics class I was tasked with doing a Polygon Filler, my software renderer is currently being coded in Python. Right now, I want to test this pointInPolygon code I found at: How can I determine whether a 2D Point is within a Polygon? so I can make my own method later on basing myself on that one.
The code is:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
And my attempt to recreate it in Python is as following:
def pointInPolygon(self, nvert, vertx, verty, testx, testy):
c = 0
j = nvert-1
for i in range(nvert):
if(((verty[i]>testy) != (verty[j]>testy)) and (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i] + vertx[i]))):
c = not c
j += 1
return c
But this obviously will return a index out of range in the second iteration because j = nvert and it will crash.
Thanks in advance.
You're reading the tricky C code incorrectly. The point of j = i++ is to both increment i by one and assign the old value to j. Similar python code would do j = i at the end of the loop:
j = nvert - 1
for i in range(nvert):
...
j = i
The idea is that for nvert == 3, the values would go
j | i
---+---
2 | 0
0 | 1
1 | 2
Another way to achieve this is that j equals (i - 1) % nvert,
for i in range(nvert):
j = (i - 1) % nvert
...
i.e. it is lagging one behind, and the indices form a ring (like the vertices do)
More pythonic code would use itertools and iterate over the coordinates themselves. You'd have a list of pairs (tuples) called vertices, and two iterators, one of which is one vertex ahead the other, and cycling back to the beginning because of itertools.cycle, something like:
# make one iterator that goes one ahead and wraps around at the end
next_ones = itertools.cycle(vertices)
next(next_ones)
for ((x1, y1), (x2, y2)) in zip(vertices, next_ones):
# unchecked...
if (((y1 > testy) != (y2 > testy))
and (testx < (x2 - x1) * (testy - y1) / (y2-y1 + x1))):
c = not c

Restricted integer partitions in Python

I want to find out how many ways there are to make 500 using only 1, 2, 5, 10, 20, 50, 100, and 200.
I understand that there exist greedy algorithms etc that can solve this type of question, but I want to be able to do it the following way:
The number of integer partitions of a given number, n, using only numbers from some set T, can be obtained from the coefficient of the xn term in the product of all (1-xt)-1, where t is in T.
To do this, note that the Taylor expansion of (1-xt)-1 equals (1+xt+x2t+...).
Here is the code I've written so far:
#################################
# First, define a function that returns the product of two
# polynomials. A list here
# represents a polynomial with the entry in a list corresponding to
# the coefficient of the power of x associated to that position, e.g.
# [1,2,3] = 1 + 2x + 3x^2.
#################################
def p(a,v):
"""(list,list) -> list"""
prodav = [0]*(len(a)+len(v)-1)
for n in range(len(a)):
for m in range(len(v)):
prodav[n+m] += v[m]*a[n]
return prodav
#################################
# Now, let a,b,c,...,h represent the first 501 terms in the Taylor
# expansion of 1/(1-x^n), where n gives the coin value, i.e
# 1,2,5,10,20,50,100,200 in pence. See the generating function
# section in https://en.wikipedia.org/wiki/Partition_(number_theory).
# Our function, p, multiplies all these polynomials together
# (when applied iteratively). As per the Wiki entry, the coefficient
# of x^t is equal to the number of possible ways t can be made,
# using only the denominations of change available, a so called
# 'restricted integer partition'. Note that it isn't necessary to
# consider the entire Taylor expansion since we only need the
# 500th power.
#################################
a = ( [1] ) * 501 # 1
b = ( [1] + [0] ) * 250 + [1] # 2
c = ( [1] + [0]*4 ) * 100 + [1] # 5
d = ( [1] + [0]*9 ) * 50 + [1] # 10
e = ( [1] + [0]*19 ) * 25 + [1] # 20
f = ( [1] + [0]*49 ) * 10 + [1] # 50
g = ( [1] + [0]*99 ) * 5 + [1] # 100
h = ( [1] + [0]*199 ) * 2 + [0]*101 # 200
x = p(h,p(g,p(f,p(e,p(d,p(c,p(b,a)))))))
print(x[500]) # = 6290871
My problem is that I'm not confident the answer this gives is correct. I've compared it to two other greedy algorithms whose outputs agree with each other, but not mine. Can anyone see where I might have gone wrong?

Python-remove highly similar string from dataset

I have a genomic dataset contained base messages, like this:
Position samp1 samp2 samp2 samp3 samp4 samp5 samp6 ...
posA T T T T T T T ...
posB G A A G G A A ...
posC G G G G G G G ...
...
This file has 100000+ lines, each line contains 200 bases of 200 samples.
Now i want to remove positons which haves high similar base in every samples, pic below is of 100 % the same, and i will remove one of them
we defined similar ratio as (similar base number) / (sequence length):
posH C C C C C C C C
posI A C C C A C C C
similarity of posH and posI is 6 / 8 = 75%
As required, similar ratio above 99% is regarded as highly similay, and remove one of the similar positions.
How can i do this work in python efficiently?
Thank you.
Similarity of 6/8 between posH and posI, looks like you want inverse of normalized hamming distance (i.e. 1-d).
You can compute inverse normalized hamming distance between two sequences using:
def inverse_hamming_distance(a,b):
z = list(zip(a, b))
return sum(e[0]==e[1] for e in z) / len(z)
and it gives:
>>> inverse_hamming_distance('CCCCCCCC', 'ACCCACCC')
0.75
However you can save some CPU cycle by early detecting that two lines are not similar. Given the minimum similarity threshold t, if you observe int(0.5+(1-t)*len(z)) dissimilar items, you don't need to go til the end, and you can already tell items are not similar.
def similar(a,b,t=0.99):
l = min(len(a), len(b))
t = int(0.5 + l*(1 - t))
n = 0
for a1, b1 in zip(a, b):
if a1 != b1:
n += 1
if n > t:
return False
return True
test:
>>> similar('CCCCCCCC', 'ACCCACCC', 0.75)
True
>>> similar('CCCCCCCC', 'ACCCACCC', 0.9)
False
First to speed this up a lot, start by storing all the data as lists of integers or binary before comparing. Either would dramatically reduce the memory required for the comparison operation. An enumerable would be a good fit. When you do this I would also split each dictionary value into a list with each item a specific sample: basedict = { 'posA' : [samp1, samp2,...] , ... }.
from enum import Enum
Base = Enum('Base', 'A C T G')
#mescalinum's answer has a good description on how to use a function to calculate whether two lines are similar:
def similar(a,b,t=0.99):
l = min(len(a), len(b))
t = int(0.5 + l*(1 - t))
n = 0
for a1, b1 in zip(a, b):
if a1 != b1:
n += 1
if n > t:
return False
return True
All that's left is to make a loop that works for your dataset. similarpositions gives a list of the keys to every position deemed 'similar.'
similarpositions = []
for key in basedict:
samplecomps = (len(basedict[key]) * (len(basedict[key]) - 1)) / 2 # number of comparisons between samples needed
dissimilar = 0
for item1 in basedict[key]:
for item2 in basedict[key]:
if similar(item1, item2, 0.99) == False:
dissimilar += 1
if samplecomps / dissimilar > 0.01: // break once we know too many dissimilar results, to save unneeded comparisions
break
if samplecomps / dissimilar > 0.01:
break
if samplecomps / dissimilar <= 0.01:
similarpositions.append(key)

NeedlemanWunsch algorithm

I'm trying to understand the Hirschberg algorithm and I came across this piece of algorithm from Wikipedia. I do not understand how the NeedlemanWunsch() function works.
function Hirschberg(X,Y)
Z = ""
W = ""
if length(X) == 0 or length(Y) == 0
if length(X) == 0
for i=1 to length(Y)
Z = Z + '-'
W = W + Yi
end
else if length(Y) == 0
for i=1 to length(X)
Z = Z + Xi
W = W + '-'
end
end
else if length(X) == 1 or length(Y) == 1
(Z,W) = NeedlemanWunsch(X,Y)
else
xlen = length(X)
xmid = length(X)/2
ylen = length(Y)
ScoreL = NWScore(X1:xmid, Y)
ScoreR = NWScore(rev(Xxmid+1:xlen), rev(Y))
ymid = PartitionY(ScoreL, ScoreR)
(Z,W) = Hirschberg(X1:xmid, y1:ymid) + Hirschberg(Xxmid+1:xlen, Yymid+1:ylen)
end
return (Z,W)
Can someone explain about the NeedlemanWunsch algorithm and how can it be implemented through Python? Thank you very much!
This looks like a homework/coursework question so I won't give you the full solution. However, I will guide you into producing a working solution.
Needleman-Wunsch Algorithm
The Needleman-Wunsch algorithm is a method used to align sequences. It is essentially made up of two components:
A similarity matrix, F.
A linear penalty gap, d.
When aligning sequences, there can be many possibilities. What this matrix allows you to do is to find the most optimal one and discard all the other sequences.
What you will have to do is:
Create a 2-dimensional array to hold the matrix, F.
A method to initialise matrix F with the scores.
A method to compute the optimal sequence.
Creating a 2-dimensional array to hold the matrix, F
You can either use numpy for this, or you could just generate the matrix as follows. Assume you have two sequences A and B:
F = [[0 for x in xrange(len(A)] for x in xrange(len(B))]
A method to initialise matrix F with the scores.
Create a method which takes a parameters the length of each sequence, the linear penalty gap, and the matrix F:
def createSimilarityMatrix(lengthOfA, lengthOfB, penalityGap, F):
You then need to implement the following pseudo-code:
for i=0 to length(A)
F(i,0) ← d*i
for j=0 to length(B)
F(0,j) ← d*j
for i=1 to length(A)
for j=1 to length(B)
{
Match ← F(i-1,j-1) + S(Ai, Bj)
Delete ← F(i-1, j) + d
Insert ← F(i, j-1) + d
F(i,j) ← max(Match, Insert, Delete)
}
Hint: Research optimal ways to write this algorithm in idiomatic Python. Also note that in the double for-loop at the bottom, you can collapse in a one-liner.
A method to compute the optimal sequence
Once you have the similarity matrix done, then you can implement the main algorithm to compute the optimal sequence. For this, create a method which takes your two sequences A and B as parameters:
def needlemanWunsch (a, b):
You will then need to implement this method using the following pseudocode:
AlignmentA ← ""
AlignmentB ← ""
i ← length(A)
j ← length(B)
while (i > 0 or j > 0)
{
if (i > 0 and j > 0 and F(i,j) == F(i-1,j-1) + S(Ai, Bj))
{
AlignmentA ← Ai + AlignmentA
AlignmentB ← Bj + AlignmentB
i ← i - 1
j ← j - 1
}
else if (i > 0 and F(i,j) == F(i-1,j) + d)
{
AlignmentA ← Ai + AlignmentA
AlignmentB ← "-" + AlignmentB
i ← i - 1
}
else (j > 0 and F(i,j) == F(i,j-1) + d)
{
AlignmentA ← "-" + AlignmentA
AlignmentB ← Bj + AlignmentB
j ← j - 1
}
}
The psuedo-code has been taken from this page on Wikipedia. For more information on the Needleman-Wunsch algorithm, please have a look at this presentation.

Solving Puzzle in Python

I got one puzzle and I want to solve it using Python.
Puzzle:
A merchant has a 40 kg weight which he used in his shop. Once, it fell
from his hands and was broken into 4 pieces. But surprisingly, now he
can weigh any weight between 1 kg to 40 kg with the combination of
these 4 pieces.
So question is, what are weights of those 4 pieces?
Now I wanted to solve this in Python.
The only constraint i got from the puzzle is that sum of 4 pieces is 40. With that I could filter all the set of 4 values whose sum is 40.
import itertools as it
weight = 40
full = range(1,41)
comb = [x for x in it.combinations(full,4) if sum(x)==40]
length of comb = 297
Now I need to check each set of values in comb and try all the combination of operations.
Eg if (a,b,c,d) is the first set of values in comb, I need to check a,b,c,d,a+b,a-b, .................a+b+c-d,a-b+c+d........ and so on.
I tried a lot, but i am stuck at this stage, ie how to check all these combination of calculations to each set of 4 values.
Question :
1) I think i need to get a list all possible combination of [a,b,c,d] and [+,-].
2) does anyone have a better idea and tell me how to go forward from here?
Also, I want to do it completely without help of any external libraries, need to use only standard libraries of python.
EDIT : Sorry for the late info. Its answer is (1,3,9,27), which I found a few years back. I have checked and verified the answer.
EDIT : At present, fraxel's answer works perfect with time = 0.16 ms. A better and faster approach is always welcome.
Regards
ARK
Earlier walk-through anwswer:
We know a*A + b*B + c*C + d*D = x for all x between 0 and 40, and a, b, c, d are confined to -1, 0, 1. Clearly A + B + C + D = 40. The next case is x = 39, so clearly the smallest move is to remove an element (it is the only possible move that could result in successfully balancing against 39):
A + B + C = 39, so D = 1, by neccessity.
next:
A + B + C - D = 38
next:
A + B + D = 37, so C = 3
then:
A + B = 36
then:
A + B - D = 35
A + B - C + D = 34
A + B - C = 33
A + B - C - D = 32
A + C + D = 31, so A = 9
Therefore B = 27
So the weights are 1, 3, 9, 27
Really this can be deduced immediately from the fact that they must all be multiples of 3.
Interesting Update:
So here is some python code to find a minimum set of weights for any dropped weight that will span the space:
def find_weights(W):
weights = []
i = 0
while sum(weights) < W:
weights.append(3 ** i)
i += 1
weights.pop()
weights.append(W - sum(weights))
return weights
print find_weights(40)
#output:
[1, 3, 9, 27]
To further illustrate this explaination, one can consider the problem as the minimum number of weights to span the number space [0, 40]. It is evident that the number of things you can do with each weight is trinary /ternary (add weight, remove weight, put weight on other side). So if we write our (unknown) weights (A, B, C, D) in descending order, our moves can be summarised as:
ABCD: Ternary:
40: ++++ 0000
39: +++0 0001
38: +++- 0002
37: ++0+ 0010
36: ++00 0011
35: ++0- 0012
34: ++-+ 0020
33: ++-0 0021
32: ++-- 0022
31: +0++ 0100
etc.
I have put ternary counting from 0 to 9 alongside, to illustrate that we are effectively in a trinary number system (base 3). Our solution can always be written as:
3**0 + 3**1 +3**2 +...+ 3**N >= Weight
For the minimum N that this holds true. The minimum solution will ALWAYS be of this form.
Furthermore, we can easily solve the problem for large weights and find the minimum number of pieces to span the space:
A man drops a known weight W, it breaks into pieces. His new weights allow him to weigh any weight up to W. How many weights are there, and what are they?
#what if the dropped weight was a million Kg:
print find_weights(1000000)
#output:
[1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 202839]
Try using permutations for a large weight and unknown number of pieces!!
Here is a brute-force itertools solution:
import itertools as it
def merchant_puzzle(weight, pieces):
full = range(1, weight+1)
all_nums = set(full)
comb = [x for x in it.combinations(full, pieces) if sum(x)==weight]
funcs = (lambda x: 0, lambda x: x, lambda x: -x)
for c in comb:
sums = set()
for fmap in it.product(funcs, repeat=pieces):
s = sum(f(x) for x, f in zip(c, fmap))
if s > 0:
sums.add(s)
if sums == all_nums:
return c
>>> merchant_puzzle(40, 4)
(1, 3, 9, 27)
For an explanation of how it works, check out the answer Avaris gave, this is an implementation of the same algorithm.
You are close, very close :).
Since this is a puzzle you want to solve, I'll just give pointers. For this part:
Eg if (a,b,c,d) is the first set of values in comb, i need to check
a,b,c,d,a+b,a-b, .................a+b+c-d,a-b+c+d........ and so on.
Consider this: Each weight can be put to one scale, the other or neither. So for the case of a, this can be represented as [a, -a, 0]. Same with the other three. Now you need all possible pairings with these 3 possibilities for each weight (hint: itertools.product). Then, a possible measuring of a pairing (lets say: (a, -b, c, 0)) is merely the sum of these (a-b+c+0).
All that is left is just checking if you could 'measure' all the required weights. set might come handy here.
PS: As it was stated in the comments, for the general case, it might not be necessary that these divided weights should be distinct (for this problem it is). You might reconsider itertools.combinations.
I brute forced the hell out of the second part.
Do not click this if you don't want to see the answer. Obviously, if I was better at permutations, this would have required a lot less cut/paste search/replace:
http://pastebin.com/4y2bHCVr
I don't know Python syntax, but maybe you can decode this Scala code; start with the 2nd for-loop:
def setTo40 (a: Int, b: Int, c: Int, d: Int) = {
val vec = for (
fa <- List (0, 1, -1);
fb <- List (0, 1, -1);
fc <- List (0, 1, -1);
fd <- List (0, 1, -1);
prod = fa * a + fb * b + fc * c + fd * d;
if (prod > 0)
) yield (prod)
vec.toSet
}
for (a <- (1 to 9);
b <- (a to 14);
c <- (b to 20);
d = 40-(a+b+c)
if (d > 0)) {
if (setTo40 (a, b, c, d).size > 39)
println (a + " " + b + " " + c + " " + d)
}
With weights [2, 5, 15, 18] you can also measure all objects between 1 and 40kg, although some of them will need to be measured indirectly. For example, to measure an object weighting 39kg, you would first compare it with 40kg and the balance would pend to the 40kg side (because 39 < 40), but then if you remove the 2kg weight it would pend to the other side (because 39 > 38) and thus you can conclude the object weights 39kg.
More interestingly, with weights [2, 5, 15, 45] you can measure all objects up to 67kg.
If anyone doesn't want to import a library to import combos/perms, this will generate all possible 4-move strategies...
# generates permutations of repeated values
def permutationsWithRepeats(n, v):
perms = []
value = [0] * n
N = n - 1
i = n - 1
while i > -1:
perms.append(list(value))
if value[N] < v:
value[N] += 1
else:
while (i > -1) and (value[i] == v):
value[i] = 0
i -= 1
if i > -1:
value[i] += 1
i = N
return perms
# generates the all possible permutations of 4 ternary moves
def strategy():
move = ['-', '0', '+']
perms = permutationsWithRepeats(4, 2)
for i in range(len(perms)):
s = ''
for j in range(4):
s += move[perms[i][j]]
print s
# execute
strategy()
My solution as follows:
#!/usr/bin/env python3
weight = 40
parts = 4
part=[0] * parts
def test_solution(p, weight,show_result=False):
cv=[0,0,0,0]
for check_weight in range(1,weight+1):
sum_ok = False
for parts_used in range(2 ** parts):
for options in range(2 ** parts):
for pos in range(parts):
pos_neg = int('{0:0{1}b}'.format(options,parts)[pos]) * 2 - 1
use = int('{0:0{1}b}'.format(parts_used,parts)[pos])
cv[pos] = p[pos] * pos_neg * use
if sum(cv) == check_weight:
if show_result:
print("{} = sum of:{}".format(check_weight, cv))
sum_ok = True
break
if sum_ok:
continue
else:
return False
return True
for part[0] in range(1,weight-parts):
for part[1] in range(part[0]+1, weight - part[0]):
for part[2] in range( part[1] + 1 , weight - sum(part[0:2])):
part[3] = weight - sum(part[0:3])
if test_solution(part,weight):
print(part)
test_solution(part,weight,True)
exit()
It gives you all the solutions for the given weights
More dynamic than my previous answer, so it also works with other numbers. But breaking up into 5 peaces takes some time:
#!/usr/bin/env python3
weight = 121
nr_of_parts = 5
# weight = 40
# nr_of_parts = 4
weight = 13
nr_of_parts = 3
part=[0] * nr_of_parts
def test_solution(p, weight,show_result=False):
cv=[0] * nr_of_parts
for check_weight in range(1,weight+1):
sum_ok = False
for nr_of_parts_used in range(2 ** nr_of_parts):
for options in range(2 ** nr_of_parts):
for pos in range(nr_of_parts):
pos_neg = int('{0:0{1}b}'.format(options,nr_of_parts)[pos]) * 2 - 1
use = int('{0:0{1}b}'.format(nr_of_parts_used,nr_of_parts)[pos])
cv[pos] = p[pos] * pos_neg * use
if sum(cv) == check_weight:
if show_result:
print("{} = sum of:{}".format(check_weight, cv))
sum_ok = True
break
if sum_ok:
continue
else:
return False
return True
def set_parts(part,position, nr_of_parts, weight):
if position == 0:
part[position] = 1
part, valid = set_parts(part,position+1,nr_of_parts,weight)
return part, valid
if position == nr_of_parts - 1:
part[position] = weight - sum(part)
if part[position -1] >= part[position]:
return part, False
return part, True
part[position]=max(part[position-1]+1,part[position])
part, valid = set_parts(part, position + 1, nr_of_parts, weight)
if not valid:
part[position]=max(part[position-1]+1,part[position]+1)
part=part[0:position+1] + [0] * (nr_of_parts - position - 1)
part, valid = set_parts(part, position + 1, nr_of_parts, weight)
return part, valid
while True:
part, valid = set_parts(part, 0, nr_of_parts, weight)
if not valid:
print(part)
print ('No solution posible')
exit()
if test_solution(part,weight):
print(part,' ')
test_solution(part,weight,True)
exit()
else:
print(part,' ', end='\r')

Categories

Resources