Write code that find maximum cuts of an iron bar - python

I'm currently trying to write a Python programm that can find the maxium cuts for a 5m iron bar.
The allowed cuts are : 0.5m, 1m, 1.2m, and 2m.
Given that I have to find all the combinations that match or get close to 5m.
Combinations exemple:
10*0.5 = 5m
7*0.5 + 1.2 = 4.7m
The second combination is also good because we cant produce a 0.3m cut so we throw it away.
The order inside a combination dosent matter,
7x0.5 + 1.2 = 1.2 + 7x0.5
so we have to count it only once.
So ideally my programm take a file in, and write a file with all the combinations like:
c1 = 10*0.5
c2 = 7*0.5 + 1.2
....
Can anyone share advice from where to start please ? Thank you.

Perhaps this is what you are looking for ?
x = [2, 1.2, 1, 0.5]
max_val = 5
def find_next(state, idx, check=False):
if(idx == len(x)):
return print_it(state, check)
if(sum(state) + x[idx] > max_val):
find_next(state, idx + 1, True)
else:
find_next(state + [x[idx]], idx)
find_next(state, idx + 1)
def print_it(state, check):
if check:
print("")
print(sum(state),state)
return
find_next([],0)
It recursively finds the next value until it runs out of values, and it tracks the current state with a simple list which it prints with print_it function. I will leave the formatting and file storage up to you, which can easily be implemented in that function.

Related

Python For loop not incrementing

clean_offset = len(malware)
tuple_clean = []
tuple_malware = []
for i in malware:
tuple_malware.append([malware.index(i), 0])
print(malware.index(i))
print(tuple_malware)
for j in clean:
tuple_clean.append([(clean_offset + clean.index(j)), 1])
print(clean.index(j))
print(tuple_clean)
import pdb; pdb.set_trace()
training_data_size_mal = 0.8 * len(malware)
training_data_size_clean = 0.8 * len(clean)
i increments as normal and produces correct output however j remains at 0 for three loops and then jumps to 3. I don't understand this.
There is a logical error on clean.index(j).
Array.index will return the first matched index in that array.
So if there are some equal variables there will be some error
You can inspect with below code.
malware = [1,2,3,4,5,6,7,8,8,8,8,8,2]
clean = [1,2,3,4,4,4,4,4,4,2,4,4,4,4]
clean_offset = len(malware)
tuple_clean = []
tuple_malware = []
for i in malware:
tuple_malware.append([malware.index(i), 0])
print(malware.index(i))
print(tuple_malware)
for j in clean:
tuple_clean.append([(clean_offset + clean.index(j)), 1])
print(clean.index(j))
print(tuple_clean)
training_data_size_mal = 0.8 * len(malware)
training_data_size_clean = 0.8 * len(clean)
for a in something
a is what is contained in something, not the index
for example:
for n in [1, 10, 9, 3]:
print(n)
gives
1
10
9
3
You either want
for i in range(len(malware))
or
for i, element in enumerate(malware)
at which point the i is the count and the element in the malware.index(i)
The last one is considered best practice when needing both the index and the element at that index in the loop.
op has already figured the question, but in case anyone is wondering or needs a TL;DR of Barkin's comment, its just a small correction,
replace
for i in malware
for j in clean
with
for i in range(len(malware))
for j in range(len(clean))
and at the end remove the .index() function, and place i and j.

different result from recursive and dynamic programming

Working on below problem,
Problem,
Given a m * n grids, and one is allowed to move up or right, find the different paths between two grid points.
I write a recursive version and a dynamic programming version, but they return different results, and any thoughts what is wrong?
Source code,
from collections import defaultdict
def move_up_right(remaining_right, remaining_up, prefix, result):
if remaining_up == 0 and remaining_right == 0:
result.append(''.join(prefix[:]))
return
if remaining_right > 0:
prefix.append('r')
move_up_right(remaining_right-1, remaining_up, prefix, result)
prefix.pop(-1)
if remaining_up > 0:
prefix.append('u')
move_up_right(remaining_right, remaining_up-1, prefix, result)
prefix.pop(-1)
def move_up_right_v2(remaining_right, remaining_up):
# key is a tuple (given remaining_right, given remaining_up),
# value is solutions in terms of list
dp = defaultdict(list)
dp[(0,1)].append('u')
dp[(1,0)].append('r')
for right in range(1, remaining_right+1):
for up in range(1, remaining_up+1):
for s in dp[(right-1,up)]:
dp[(right,up)].append(s+'r')
for s in dp[(right,up-1)]:
dp[(right,up)].append(s+'u')
return dp[(right, up)]
if __name__ == "__main__":
result = []
move_up_right(2,3,[],result)
print result
print '============'
print move_up_right_v2(2,3)
In version 2 you should be starting your for loops at 0 not at 1. By starting at 1 you are missing possible permutations where you traverse the bottom row or leftmost column first.
Change version 2 to:
def move_up_right_v2(remaining_right, remaining_up):
# key is a tuple (given remaining_right, given remaining_up),
# value is solutions in terms of list
dp = defaultdict(list)
dp[(0,1)].append('u')
dp[(1,0)].append('r')
for right in range(0, remaining_right+1):
for up in range(0, remaining_up+1):
for s in dp[(right-1,up)]:
dp[(right,up)].append(s+'r')
for s in dp[(right,up-1)]:
dp[(right,up)].append(s+'u')
return dp[(right, up)]
And then:
result = []
move_up_right(2,3,[],result)
set(move_up_right_v2(2,3)) == set(result)
True
And just for fun... another way to do it:
from itertools import permutations
list(map(''.join, set(permutations('r'*2+'u'*3, 5))))
The problem with the dynamic programming version is that it doesn't take into account the paths that start from more than one move up ('uu...') or more than one move right ('rr...').
Before executing the main loop you need to fill dp[(x,0)] for every x from 1 to remaining_right+1 and dp[(0,y)] for every y from 1 to remaining_up+1.
In other words, replace this:
dp[(0,1)].append('u')
dp[(1,0)].append('r')
with this:
for right in range(1, remaining_right+1):
dp[(right,0)].append('r'*right)
for up in range(1, remaining_up+1):
dp[(0,up)].append('u'*up)

More on dynamic programming

Two weeks ago I posted THIS question here about dynamic programming. User Andrea Corbellini answered precisely what I wanted, but I wanted to take the problem one more step further.
This is my function
def Opt(n):
if len(n) == 1:
return 0
else:
return sum(n) + min(Opt(n[:i]) + Opt(n[i:])
for i in range(1, len(n)))
Let's say you would call
Opt( [ 1,2,3,4,5 ] )
The previous question solved the problem of computing the optimal value. Now,
instead of the computing the optimum value 33 for the above example, I want to print the way we got to the most optimal solution (path to the optimal solution). So, I want to print the indices where the list got cut/divided to get to the optimal solution in the form of a list. So, the answer to the above example would be :
[ 3,2,1,4 ] ( Cut the pole/list at third marker/index, then after second index, then after first index and lastly at fourth index).
That is the answer should be in the form of a list. The first element of the list will be the index where the first cut/division of the list should happen in the optimal path. The second element will be the second cut/division of the list and so on.
There can also be a different solution:
[ 3,4,2,1 ]
They both would still lead you to the correct output. So, it doesn't matter which one you printed. But, I have no idea how to trace and print the optimal path taken by the Dynamic Programming solution.
By the way, I figured out a non-recursive solution to that problem that was solved in my previous question. But, I still can't figure out to print the path for the optimal solution. Here is the non-recursive code for the previous question, it might be helpful to solve the current problem.
def Opt(numbers):
prefix = [0]
for i in range(1,len(numbers)+1):
prefix.append(prefix[i-1]+numbers[i-1])
results = [[]]
for i in range(0,len(numbers)):
results[0].append(0)
for i in range(1,len(numbers)):
results.append([])
for j in range(0,len(numbers)):
results[i].append([])
for i in range(2,len(numbers)+1): # for all lenghts (of by 1)
for j in range(0,len(numbers)-i+1): # for all beginning
results[i-1][j] = results[0][j]+results[i-2][j+1]+prefix[j+i]-prefix[j]
for k in range(1,i-1): # for all splits
if results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j] < results[i-1][j]:
results[i-1][j] = results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j]
return results[len(numbers)-1][0]
Here is one way of printing the selected :
I used the recursive solution using memoization provided by #Andrea Corbellini in your previous question. This is shown below:
cache = {}
def Opt(n):
# tuple objects are hashable and can be put in the cache.
n = tuple(n)
if n in cache:
return cache[n]
if len(n) == 1:
result = 0
else:
result = sum(n) + min(Opt(n[:i]) + Opt(n[i:])
for i in range(1, len(n)))
cache[n] = result
return result
Now, we have the cache values for all the tuples including the selected ones.
Using this, we can print the selected tuples as shown below:
selectedList = []
def printSelected (n, low):
if len(n) == 1:
# No need to print because it's
# already printed at previous recursion level.
return
minVal = math.Inf
minTupleLeft = ()
minTupleRight = ()
splitI = 0
for i in range(1, len(n)):
tuple1ToI = tuple (n[:i])
tupleiToN = tuple (n[i:])
if (cache[tuple1ToI] + cache[tupleiToN]) < minVal:
minVal = cache[tuple1ToI] + cache[tupleiToN]
minTupleLeft = tuple1ToI
minTupleRight = tupleiToN
splitI = low + i
print minTupleLeft, minTupleRight, minVal
print splitI # OP just wants the split index 'i'.
selectedList.append(splitI) # or add to the list as requested by OP
printSelected (list(minTupleLeft), low)
printSelected (list(minTupleRight), splitI)
You call the above method like shown below:
printSelected (n, 0)

In python, how would I go about linking user input to a index in a list?

I would like to create a binary puzzle with python.
At the moment I already made a 6x6, 8x8 and 10x10 layout which is shown based on the difficulty that the players wishes to play. The purpose of the puzzle can be compared with a game of sudoku, you want to input either 0 or 1 on a given location by the player. Below you will find what I currently have for the layout.
if graad == 1:
easy = [['A', 'B', 'C', 'D', 'E'],
['_','_','_','_','_','_','_'],
[0,1,0,1,0,1,' |1'],
[1,0,1,0,1,0,' |2'],
[0,1,0,1,0,1,' |3'],
[1,0,1,0,1,0,' |4'],
[0,1,0,1,0,1,' |5'],
[1,0,1,0,1,0,' |6']]
i = 0
while i < len(easy):
j = 0
s = ""
while j < len(easy[i]):
s = s + str(easy[i][j]) + " "
j = j + 1
print (s)
i = i + 1
Now the problem that I am facing is, how can I let python know that when a player fills in position 3 on column C and row 5 with a 0 for example?
I was thinking of an IF statement that checks the input on either a A, B, C D, E... Row 1,2,3,4,5.. but that is going to be a lot of if statements.
Edit1: Ok so to clarify.I wanted to post a picture but need more posts.
For example, I have a game board of 6x6 cells. Some of them are filled with a 1 and some of them are filled with 0 and most of them are empty because the goal is to have it look in the end like my layout in the python code.(That's the solution). So you want the user to fill in those empty cells.
Now, let's say that the player wants to fill in A-1 with a 1, how will python know that input A-1 is linked to index [0][0] in the list?
A simple way to convert your letter indices to numbers is to use the ord() function, which returns the numerical code of a single character. Since you are using upper-case letters, with 'A' being the label for the column with index 0, you can do
column = ord(letter) - ord('A')
That will convert 'A' to 0, 'B' to 1, etc.
Here's a short example program vaguely based on the code on your question.
It accepts moves in the form A10 to set location A1 to '1', 'B30' to set location B3 to '0'. It accepts lower case letters, too, so 'd11' is the same as 'D11'. Hit Ctrl-C to exit.
Tested on Python 2.6.6, but it should work correctly on Python 3. (To run it on Python 2, change input() to raw_input()).
#! /usr/bin/env python
def print_grid(g):
gsize = len(g)
base = ord('A')
print(' '.join([chr(base + i) for i in range(gsize)]))
print((gsize * 2) * '-')
for i, row in enumerate(g, 1):
print(' '.join(row) + ' | ' + str(i))
print('\n')
def main():
gsize = 9
rowstr = gsize * '_'
grid = [list(rowstr) for i in range(gsize)]
print_grid(grid)
while True:
move = input('Enter move: ')
letter, number, bit = move.strip()
col = ord(letter.upper()) - ord('A')
row = int(number) - 1
grid[row][col] = bit
print_grid(grid)
if __name__ == "__main__":
main()
If you work with a pandas DataFrame to hold your correct answer of the game you can easily check things. The pandas package has a good documentation (and a lot of Q&A here on stackoverflow).
The setup of your correct answer:
import pandas as pd
data = [[0,1,0,1,0,1],
[1,0,1,0,1,0],
[0,1,0,1,0,1],
[1,0,1,0,1,0],
[0,1,0,1,0,1],
[1,0,1,0,1,0]]
easy = pd.DataFrame(data)
easy.columns = ['A','B','C','D','E','F']
print easy
The item at position 'A',0 (python starts to number from 0) is given by easy['A'][0]. For more information about indexing a pandas DataFrame object visit the documentation.
Another usefull thing, a DataFrame object is printable, making it unnecessary to write a print command yourself.
If using DataFrames is overkill for you, another option is to work with a 'translation' dictionary. This dictionary will use the letters for keys and the corresponding column number as a value.
>>> column = {'A':0, 'B':1, 'C':2, 'D':3, 'E':4, 'F':5}
>>> print column['A']
0

How to make a list of lists in python

I am trying to make a list of lists in python using random.random().
def takeStep(prevPosition, maxStep):
"""simulates taking a step between positive and negative maxStep, \
adds it to prevPosition and returns next position"""
nextPosition = prevPosition + (-maxStep + \
( maxStep - (-maxStep)) * random.random())
list500Steps = []
list1000Walks = []
for kk in range(0,1000):
list1000Walks.append(list500Steps)
for jj in range(0 , 500):
list500Steps.append(list500Steps[-1] + takeStep(0 , MAX_STEP_SIZE))
I know why this gives me what it does, just don't know how to do something about it. Please give the simplest answer, in new at this and don't know a lot yet.
for kk in xrange(0,1000):
list500steps = []
for jj in range(0,500):
list500steps.append(...)
list1000walks.append(list500steps)
Notice how I am creating an empty array (list500steps) each time in the first for loop? Then, after creating all the steps I append that array (Which is now NOT empty) to the array of walks.
import random
def takeStep(prevPosition, maxStep):
"""simulates taking a step between positive and negative maxStep, \
adds it to prevPosition and returns next position"""
nextPosition = prevPosition + (-maxStep + \
( maxStep - (-maxStep)) * random.random())
return nextPosition # You didn't have this, I'm not exactly sure what you were going for #but I think this is it
#Without this statement it will repeatedly crash
list500Steps = [0]
list1000Walks = [0]
#The zeros are place holders so for the for loop (jj) below. That way
#The first time it goes through the for loop it has something to index-
#during "list500Steps.append(list500Steps[-1] <-- that will draw an eror without anything
#in the loops. I don't know if that was your problem but it isn't good either way
for kk in range(0,1000):
list1000Walks.append(list500Steps)
for jj in range(0 , 500):
list500Steps.append(list500Steps[-1] + takeStep(0 , MAX_STEP_SIZE))
#I hope for MAX_STEP_SIZE you intend on (a) defining the variable (b) inputing in a number
You might want to print one of the lists to check the input.

Categories

Resources