I am working on an optimisation problem with Optaplanner. I have the feeling that I have not designed my planning entity or variable correctly. Maybe someone would like to say what they think about the following case:
Entities:
In principle, it is a fairly simple problem. There are a lot of warehouses that store exactly one product and that can receive products or supply other warehouses on specified transport routes. Let's call them nodes.
class Node
int upperBoundary
int lowerBoundary
int items
String name
Each transport route can transport all products. You could think of the problem as a matrix or a tree. I have defined the cells of the matrix as planning entities. The planning variable is an integer value on the cell. Let's call them weighted edges. In my Solution Class is a List<Edge> edges.
E1 E2 E3 ... En
N1 1 0 0 2
N2 3 1 3 1
N3 0 1 0 0
...
Nn 1 1 0 0
#PlanningEntity
class WeightedEdge
Node from
Node to
#PlanningVariable
Integer items (nullable)
int minCapacity
int maxCapacity
In my example I now have about 450 weighted edges. All of them have minimum and maximum values. These are recognised correctly.
Node a min 0 max 40
Node b min 0 max 20 uws.
If I now run a benchmark, it shows me exactly the sum of the number ranges from the individual nodes as the "problem scale". In the example above it would be 60.
But the problem is that the planning variables have dependencies. It therefore makes a difference whether I enter 39 for a and 20 for b. Or 38 for a and 20 for b. This gives me 800 possibilities. Does anyone have an idea where the design error could be in this structure?
The Scoring Function aims to balance the Nodes, so that after the planning period their amount of items is between the upper and lower boundary. For that I am using the constraintProvider.
SoftScore = Sum of to many or to few items at each station through the whole network
--- Edit ---
As suggested, I changed the environment mode to FULL_ASSERT. With this config, the solver throws an error:
with this mode it throws an error. My undoMove is corrupted:
Caused by: java.lang.IllegalStateException: UndoMove corruption (1soft): the beforeMoveScore (-65init/0hard/0medium/-2412soft) is not the undoScore (-65init/0hard/0medium/-2411soft) which is the uncorruptedScore (-65init/0hard/0medium/-2411soft) of the workingSolution.
1) Enable EnvironmentMode FULL_ASSERT (if you haven't already) to fail-faster in case there's a score corruption or variable listener corruption.
2) Check the Move.createUndoMove(...) method of the moveClass (class org.optaplanner.core.impl.heuristic.selector.move.generic.ChangeMove). The move (0 items -> 3 items) might have a corrupted undoMove (Undo(0 items -> 3 items)).
3) Check your custom VariableListeners (if you have any) for shadow variables that are used by score constraints that could cause the scoreDifference (1soft).
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.assertExpectedUndoMoveScore(AbstractScoreDirector.java:670)
at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:149)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
... 4 more
--- Edit 2: Score over time Graph ---
--- Edit 3: Memory Consumption Graph ---
Related
I was solving problems on a competitive coding website when I came across this. The problem states that:
In this game there are N levels and M types of available weapons. The levels are numbered from 0 to N-1 and the weapons are numbered from 0 to M-1 . You can clear these levels in any order. In each level, some subset of these M weapons is required to clear this level. If in a particular level, you need to buy x new weapons, you will pay x^2 coins for it. Also note that you can carry all the weapons you have currently to the next level . Initially, you have no weapons. Can you find out the minimum coins required such that you can clear all the levels?
Input Format
The first line of input contains 2 space separated integers:
N = the number of levels in the game
M = the number of types of weapons
N lines follows. The ith of these lines contains a binary string of length M. If the jth character of
this string is 1 , it means we need a weapon of type j to clear the ith level.
Constraints
1 <= N <=20
1<= M <= 20
Output Format
Print a single integer which is the answer to the problem.
Sample TestCase 1
Input
1 4
0101
Output
4
Explanation
There is only one level in this game. We need 2 types of weapons - 1 and 3. Since, initially Ben
has no weapons he will have to buy these, which will cost him 2^2 = 4 coins.
Sample TestCase 2
Input
3 3
111
001
010
Output
3
Explanation
There are 3 levels in this game. The 0th level (111) requires all 3 types of weapons. The 1st level (001) requires only weapon of type 2. The 2nd level requires only weapon of type 1. If we clear the levels in the given order(0-1-2), total cost = 3^2 + 0^2 + 0^2 = 9 coins. If we clear the levels in the order 1-2-0, it will cost = 1^2 + 1^2 + 1^2 = 3 coins which is the optimal way.
Approach
I was able to figure out that we can calculate the minimum cost by traversing the Binary Strings in a way that we purchase minimum possible weapons at each level.
One possible way could be traversing the array of binary strings and calculating the cost for each level while the array is already arranged in the correct order. The correct order should be when the Strings are already sorted i.e. 001, 010, 111 as in case of the above test case. Traversing the arrays in this order and summing up the cost for each level gives the correct answer.
Also, the sort method in java works fine to sort these Binary Strings before running a loop on the array to sum up cost for each level.
Arrays.sort(weapons);
This approach work fine for some of the test cases, however more than half of the test cases are still failing and I can't understand whats wrong with my logic. I am using bitwise operators to calculate the number of weapons needed at each level and returning their square.
Unfortunately, I cannot see the test cases that are failing. Any help is greatly appreciated.
This can be solved by dynamic programming.
The state will be the bit mask of weapons we currently own.
The transitions will be to try clearing each of the n possible levels in turn from the current state, acquiring the additional weapons we need and paying for them.
In each of the n resulting states, we take the minimum cost of the current way to achieve it and all previously observed ways.
When we already have some weapons, some levels will actually require no additional weapons to be bought; such transitions will automatically be disregarded since in such case, we arrive at the same state having paid the same cost.
We start at the state of m zeroes, having paid 0.
The end state is the bitwise OR of all the given levels, and the minimum cost to get there is the answer.
In pseudocode:
let mask[1], mask[2], ..., mask[n] be the given bit masks of the n levels
p2m = 2 to the power of m
f[0] = 0
all f[1], f[2], ..., f[p2m-1] = infinity
for state = 0, 1, 2, ..., p2m-1:
current_cost = f[state]
current_ones = popcount(state) // popcount is the number of 1 bits
for level = 1, 2, ..., n:
new_state = state | mask[level] // the operation is bitwise OR
new_cost = current_cost + square (popcount(new_state) - current_ones)
f[new_state] = min (f[new_state], new_cost)
mask_total = mask[1] | mask[2] | ... | mask[n]
the answer is f[mask_total]
The complexity is O(2^m * n) time and O(2^m) memory, which should be fine for m <= 20 and n <= 20 in most online judges.
The dynamic optimization idea by #Gassa could be extended by using A* by estimating min and max of the remaining cost, where
minRemaining(s)=bitCount(maxState-s)
maxRemaining(s)=bitCount(maxState-s)^2
Start with a priority queue - and base it on cost+minRemaining - with the just the empty state, and then replace a state from this queue that has not reached maxState with at most n new states based the n levels:
Keep track bound=min(cost(s)+maxRemaining(s)) in queue,
and initialize all costs with bitCount(maxState)^2+1
extract state with lowest cost
if state!=maxState
remove state from queue
for j in 1..n
if (state|level[j]!=state)
cost(state|level[j])=min(cost(state|level[j]),
cost(state)+bitCount(state|level[j]-state)^2
if cost(state|level[j])+minRemaining(state|level[j])<=bound
add/replace state|level[j] in queue
else break
The idea is to skip dead-ends. So consider an example from a comment
11100 cost 9 min 2 max 4
11110 cost 16 min 1 max 1
11111 cost 25 min 0 max 0
00011 cost 4 min 3 max 9
bound 13
remove 00011 and replace with 11111 (skipping 00011 since no change)
11111 cost 13 min 0 max 0
11100 cost 9 min 2 max 4
11110 cost 16 min 1 max 1
remove 11100 and replace with 11110 11111 (skipping 11100 since no change):
11111 cost 13 min 0 max 0
11110 cost 10 min 1 max 1
bound 11
remove 11110 and replace with 11111 (skipping 11110 since no change)
11111 cost 11 min 0 max 0
bound 11
Number of operations should be similar to dynamic optimization in the worst case, but in many cases it will be better - and I don't know if the worst case can occur.
The logic behind this problem is that every time you have to find the minimum count of set bits corresponding to a binary string which will contain the weapons so far got in the level.
For ex :
we have data as
4 3
101-2 bits
010-1 bits
110-2 bits
101-2 bits
now as 010 has min bits we compute cost for it first then update the current pattern (by using bitwise OR) so current pattern is 010
next we find the next min set bits wrt to current pattern
i have used the logic by first using XOR for current pattern and the given number then using AND with the current number(A^B)&A
so the bits become like this after the operation
(101^010)&101->101-2 bit
(110^010)&110->100-1 bit
now we know the min bit is 110 we pick it and compute the cost ,update the pattern and so on..
This method returns the cost of a string with respect to current pattern
private static int computeCost(String currPattern, String costString) {
int a = currPattern.isEmpty()?0:Integer.parseInt(currPattern, 2);
int b = Integer.parseInt(costString, 2);
int cost = 0;
int c = (a ^ b) & b;
cost = (int) Math.pow(countSetBits(c), 2);
return cost;
}
There is a state (territory) which is a tree rooted at node 1. All the cities (numbered from 1 to N+1)
in this state are connected via bidirectional roads. You have to add toll tax on each road. There are N roads which connect the cities of the state. You have to assign toll taxes on the roads so as to maximize the function Toll described below:
for(i=1;i<=number of cities;i++)
{
for(j=i+1;j<=number of cities;j++)
{
toll+=(toll required to pay to travel from i to j)
}
}
You have to maximize the toll tax. Assign the roads by toll taxes from the given array A(using each value exactly once). Find the maximum toll obtained.
Input Format:
First line contains
N and an integer whose value is always 2.
Then,
N roads follow containing 2 integers u and v, denoting the cities
between which the road is.
Next line contains N space separated values denoting elements of array A.
Output Format
Print the maximum toll which can be obtained.
Input Constraints
1≤N≤2∗10^5
1≤A[i]≤1000
1≤u,v≤N+1
Sample Input
2 2
1 3
2 3
5 7
Sample Output
24
Explanation
Assign 5 to edge (1- 3) and 7 to edge (2 - 3). This leads to an maximum toll tax of 24.
First, when you look at your Toll function code and Sample Input, then you'll see that this function counts just paths:
from 1 to 3
from 2 to 3
but not 3 to 1
and not 3 to 2,
because j is always more than i, so this leads us that 24 is incorrect answer (or you have incorrect Toll) function.
Second, according to the task (but I believe it just was described wrong) the answer will be always equal to sum of elements from array A, because the task sounds like : put elements to a symmetric matrix and then calculate a sum above (or below) a diagonal, but it is going to be all of the same elements from array A.
The Question you asked belongs to Graph.
Three cities are given from 1 -> 3. If you randomly assign values from A[] and use that in the toll function you will get the following output:
Assume you assigned 5 to Edge 1-3, and 7 to edge 2-3,
The graph would be like 1------3------2
Then According to the toll function, you will get the following routes:
1-2 === 7 + 5 = 12
1-3 === 5
2-3 === 7
So , the total toll would be = 12+5+7 = 24.
Hence, you need to first construct the graph . then assign the tolls randomly and find toll money for all the possible combinations.
or else,
you can use concept of Minimum Spanning Tree for Graph. You just need to inverse the use of kruskal or Prim's algorithm to find a route with maximum toll
PS: The meaning of bi-directional road is that suppose your first for loop starts from 3 and second for loop starts from 1, then you can also go 3->1 whose toll would be same as you used before for 1->3.
Hope this helps. :)
I was solving a problem which states following:
There are n buckets in a row. A gardener waters the buckets. Each day he waters the buckets between positions i and j (inclusive). He does this for t days for different i and j.
Output the volume of the waters in the buckets assuming initially zero volume and each watering increases the volume by 1.
Input: first line contains t and n seperated by spaces.
The next t lines contain i and j seperated by spaces.
Output: a single line showing the volume in the n buckets seperated by spaces.
Example:
Input:
2 2
1 1
1 2
Output:
2 1
Constraints:
0 <= t <= 104; 1 <= n <= 105
I tried this problem. But I use O(n*t) algorithm. I increment each time the bucket from i to j at each step. But this shows time limit error. Is there any efficient algorithm to solve this problem. A small hint would suffice.
P.S: I have used C++ and Java as tags bcoz the program can be programmed in both the languages.
Instead of remembering the amount of water in each bucket, remember the difference between each bucket and the previous one.
have two lists of the intervals, one sorted by upper, one by lower bound
then iterate over n starting with a volume v of 0.
On each iteration over n
check if the next interval starts at n
if so increase v by one and check the next interval.
do the same for the upper bounds but decrease the volume
print v
repeat with the next n
I think the key observation here is that you need to figure out a way to represent your (possibly) 105 buckets without actually allocating space for each and every one of them, and tracking them separately. You need to come up with a sparse representation to track your buckets, and the water inside.
The fact that your input comes in ranges gives you a good hint: you should probably make use of ranges in your sparse representation. You can do this by just tracking the buckets on the ends of each range.
I suggest you do this with a linked list. Each list node will contain 2 pieces of information:
a bucket number
the amount of water in that bucket
You assume that all buckets between the current bucket and the next bucket have the same volume of water.
Here's an example:
Input:
5 30
1 5
4 20
7 13
25 30
19 27
Here's what would happen on each step of the algorithm, with step 1 being the initial state, and each successive step being what you do after parsing a line.
1:0→NULL (all buckets are 0)
1:1→6:0→NULL (1-5 have 1, rest are 0)
1:1→4:2→6:1→21:0→NULL (1-3 have 1, 4-5 have 2, 6-20 have 1, rest have 0)
1:1→4:2→6:1→7:2→14:1→21:0→NULL
1:1→4:2→6:1→7:2→14:1→21:0→25:1→NULL
1:1→4:2→6:1→7:2→14:1→19:2→21:1→25:2→28:1→NULL
You should be able to infer from the above example that the complexity with this method is actually O(t2) instead of O(n×t), so this should be much faster. As I said in my comment above, the bottleneck this way should actually be the parsing and output rather than the actual computation.
Here's an algorithm with space and time complexity O(n)
I am using java since I am used to it
1) Create a hashset of n elements
2) Each time a watering is made increase the respective elements count
3) After file parsing is complete then iterate over hashset to calculate result.
I was going through data structures in java under the topic Skip list and I came across the following:
In a skip list of n nodes, for each k and i such that 1 ≤ k ≤lg n and 1 ≤ i ≤
n/2k–1⎦ – 1, the node in position 2k–1 · i points to the node in position 2k–1 · (i + 1).
This means that every second node points to the node two positions ahead, every
fourth node points to the node four positions ahead, and so on, as shown in Figure
3.17a. This is accomplished by having different numbers of reference fields in nodes
on the list: Half of the nodes have just one reference field, one-fourth of the nodes
have two reference fields, one-eighth of the nodes have three reference fields, and so
on. The number of reference fields indicates the level of each node, and the number of
levels is maxLevel = ⎣lg n⎦ + 1.
And the figure is :
A skip list with (a) evenly and (b) unevenly spaced nodes of different levels;
(c) the skip list with reference nodes clearly shown.
I don't understand the mathematical part and what exactly the sktip list is and even nodes?
Ok let me try to make you understand this.
A skip list is a data-structure which definitely makes your searches faster in a list of given elements.
A better analogy would be a network of subway in any of the bigger cities. Imagine there are 90 stations to cover and there are different lines (Green, Yellow and Blue).
The Green line only connects the stations numbered 0, 30, 60 and 90
The Yellow line connects 0, 10, 20, 30, 40, 50, 60, 70, 80 and 90
The blue line connects all the station from 0 through 90.
If you want to board the train at station 0 and want to get down at 75. What is the best strategy?
Common sense would suggest to board a train on Green line from station 0 and get down at station 60.
Board another train on Yellow line from station 60 and get down at station 70.
Board another train on Blue line from station 70 and get down at 75.
Any other way would have been more time consuming.
Now replace the stations with the nodes and lines with three individual lists (the set of these lists are called skip list).
And just imaging that you wanted to search an element at a node containing the value 75.
I hope this explains what Skip Lists are and how they are efficient.
In the traditional approach of searching, you could have visited each node and got to 75 in 75 hops.
In case of binary search you would have done it in logN
In skip list you can do the same in 1 + 1 + 15 in our particular case. You can do the math, seems to be simple though :)
EDIT: Evenly spaced nodes & Unevenly spaced nodes
As you can see my analogy, it has equal number of stations between each node on each line.
This is evenly spaced nodes. It is an ideal situation.
To understand it better we need to understand the creation of Skip Lists.
In the early stages of its construction there is only one list (the blue line) and each new node is first added to the list at an appropriate location. When the number of nodes in the blue line increases then there comes a need to create another list (yellow line) and promote one of the nodes to list 2. (PS: The first and the last element of list 1 is always promoted to the newly added list in the skip lists set). Hence, the moment a new list is added it will have three nodes.
Promotion Strategy : How to find out which node to promote from the bottom most list(blue line) to the upper lists (yellow line and green line).
The best way to decide is randomly :) So lets say upon addition of a new node, we flip a coin to see if it can be promoted to the second list. if yes, then we add it to the second list and then flip a coin again to check if it has to be added in the third list or not.
So you see, if you use this random mechanism, there might arrive situations where the nodes are unevenly spaced. :)
Hope this helps.
So I need some help coming up with a way to find a Minimum spanning tree.
Suppose I have my graph in the form of an adjacency list:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
The first letter tells which node you are looking at, and the number tells how many connections to any other node there are. For example, A has two connections - one each to B and I. After that, the number that follows the letters simply tell the weight of an edge. B has weight 12 and I has weight 25. So I had originally planned to represent this entire thing as a String array
called Graph[8]. Each line would be a different slot in the array. I am having difficulties figuring out how to accomplish this with either Prims or Kruskalls algorithm.
This isn't a direct answer to your question per-say (seems like you're doing schoolwork), but I think it will help you get started. Why not create a data structure that more closely matches your mental model and build up from there?
class GraphNode {
final String name;
final List<GraphEdge> adjacentNodes;
public GraphNode(String name) {
this.name = name;
adjacentNodes = new ArrayList<GraphEdge>();
}
public void addAdjacency(GraphNode node, int weight) {
adjacentNodes.add(new GraphEdge(node, weight));
}
}
class GraphEdge {
final GraphNode node;
final int weight;
public GraphEdge(GraphEdge node, int weight) {
this.node = node;
this.weight = weight;
}
}
Suppose I have my tree in the form of an adjacency list
It is important (for your understanding) to note that you have a connected graph in this kind of an adjacency list, but I think it was just a typo. I will propose this as an edit, but I just want you to be aware of it.
The fact that it is a graph and not a tree can be seen from those lines:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
Here you have a circle already at A-B-I:
A
12/_\25
B 8 I
Having a circle by definition means it cannot be a tree!
There is one more thing one can see from the way I presented this subgraph:
the edges have weights, not the nodes.
Now let's take a look at your provided example:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
First of all we can see that this adjacency list is either incorrect or already optimized for your needs. This can (for example) be seen from the lines
E 2 F 60 G 38
F 0
The first line here shows an edge from E to F, yet the second line says F had a degree of 0, but the degree is defined by the edges incident to it!
This is what the adjacency list would look like if it was 'complete':
A 2 B 12 I 25
B 4 A 12 C 10 H 40 I 8
C 3 B 10 D 18 G 55
D 2 C 18 E 44
E 3 D 44 F 60 G 38
F 1 E 60
G 3 C 55 E 38 H 35
H 3 B 40 G 35 I 35
We can see lots of redundancy because every edge occurs twice, this is why your 'optimized' adjacency list better suits your needs - would it be this 'complete' example one would do many useless checks.
However, you should only rely on this if you can be sure that all data given to your code is already 'optimized' (or rather in this format)! I will take this as a given from now on.
Let's talk about your data structure.
You may of course use your proposed array of strings, but to be honest, i would rather recommend something like #AmirAfghani's proposed data structure. Using his approach would make your work easier (as it - as he already pointed out - would be closer to your mental representation) and even more efficient (i guess, don't rely on this guess ;)) as you would be doing many operations on strings otherwise.
In the title you asked after Prim's algorithm, but in your actual question you said either Prim's or Kruskal's. I will go with Kruskal simply because his algorithm is way easier and you seem to accept both.
Kruskal's algorithm
Kruskal's algorithm is fairly simple, it's basically:
Start with every node, but no edges
Repeat the following as often as possible:
From all of the unused/unchosen edges choose the one with the fewest weight (if there are more than one: just pick one of them)
Check if this edge would cause a circle, if it does, mark it as chosen and 'discard' it.
If it doesn't cause a circle, use it and mark it as used/chosen.
That's all. It's really that simple.
However i would like to mention one thing at this point, i think it best fits here: there is no "the minimum spanning tree" in general, but "a minimum spanning tree" as there can be many, so your results may vary!
Back to your data structure! You may now see why it would be a bad idea to use an array of strings as a data structure. You would repeat many operations on strings (for example checking the weight of every edge) and strings are immutable, that means you cannot simply 'throw away' one of the edges or mark one of the edges in whatever way.
Using a different approach you could just set the weight to -1, or even remove the entry for the edge!
Depth-First Search
From what I have seen I think your main problem is deciding whether an edge would cause a circle or not, right?
To decide this, you will probably have to call a Depth-First Search algorithm and use its return value.
The basic idea is this: start from one of the nodes (i will call this node the root) and try to find a way to the node at the other end of the chosen edge (i will call this node the target node). (of course in the graph which doesn't have this edge yet)
Choose one unvisited edge incident to your root
Mark this chosen edge as visited (or something like that, whatever you like)
repeat the last two steps for the node on the other side of the visited edge
whenever there are no unvisited edges, go back one edge
if you are back at your root and have no unvisited edges incident to it remaining, you are done. return false.
if you at any point visit your target node, you are done. return true.
now, if this method returns true this edge would cause a circle.