Maximize the score of circular arrangement of numbers - algorithm

I am looking for an efficient algorithm to solve a problem of arranging a circular set of numbers between 1-12 to get the highest score.
The score of an arrangement is given by the sum of the score of all its adjacent pairs
To get the score of an adjacent pair (a,b), the following steps are calculated:
1. Find x such that (a+x) mod 12 = b
2. Look up x in a score table
3. The value in the score table at index 'x' is the score of the pair (a,b).
This is repeated for every adjacent pair and the sum is the score of the arrangement.
Here is an example:
Suppose the score table is [5,4,6,7,2,7,-2,-6,-8,-2,6,12,13]
Consider these numbers: 5, 12, 8, 9
For each adjacent pairs,
the values for x are: 5 -> 12: 7
12 -> 8: 8
8 -> 9: 1
9 -> 5: 8
The values for score[x] are:
score[7] = -6
score[8] = -8
score[1] = 4
score[8] = -6
The sum of the score[x] values is: (-6) + (-8) + (4) + (-6)
= -18
The goal is to come up with an algorithm to efficiently arrange the numbers to maximize the score, given the numbers themselves - up to twenty of them between 1 and 12 - and the score table.
Many thanks,

You can solve this problem with an exact TSP solver.
Imagine there's a set of cities, each which has a "value". We'll say that the value of a city x is V(x). Now imagine that to travel from city x to y it costs S(V(y) - v(X) (mod 12)). Note that S is your score table and V(y) - V(x) (mod 12) is the value to be looked up in the score table.
The goal of TSP is to find what order you should visit all the cities exactly once to optimize your cost -- in this case, you want to maximize your cost. (Alternatively, you could just make your scoring function negative and minimize your cost.)
That is, TSP will give you a permutation of the set of cities that optimize your score. Since your cities are actually the values you're interesting in permuting, it will give you a permutation of your values that produces an optimal score.
So.. Find a program or library that allows you to specify how much it costs to fly from city x to city y and then let it run and it'll give you the optimal permutation of your cities -- then you can replace the city IDs with the value (V(id)) to get the optimal solution you were looking for.
You could write your own TSP solver as well -- branch & bound techniques look popular.

Related

Algorithm to optimize a team formation based on player rating and power

I want to create an algorithm for a hypothetical game where you can create as many groups as desired with a given list of players.
Suppose I have a list of players, where every player is represented by their rating.
Given The following matrix
The numbers in yellow correspond to the amount of players in any given group.
The numbers in white correspond to the score that each player in the group is contributing.
The numbers in orange correspond to the rating threshold needed for the corresponding score.
For example, if I have a group of players of rating [50, 100], using the matrix it can be determined that they are each generating a score of 26.45, since the total rating is 150 and there are two players in that group. The total score in that team is 52.90.
Ideally the algorithm would return the groups that yield to the best score, with the constraints that I can make as many groups as wanted, and not all players need to be put in a group.
What would be a good way to get started or solve this algorithm?
I'd reduce this problem to weighted set packing and use a mixed integer program (MIP) solver library such as OR-Tools.
For every subset S of players that can form a group, we have a variable x(S) that is 1 if we choose the subset and 0 otherwise. We let the score of the subset be score(S), so that the objective is to maximize the sum over S of score(S) x(S). We have a constraint for each player p: the sum over all S containing p of x(S) is at most 1.
For example, with three players with all nonempty subsets as possible groups, we would get
maximize score({1}) x({1}) + score({2}) x({2}) + score({3}) x({3}) +
score({1,2}) x({1,2}) + score({1,3}) x({1,3}) + score({2,3}) x({2,3}) +
score({1,2,3}) x({1,2,3})
subject to
x({1}) + x({1,2}) + x({1,3}) + x({1,2,3}) <= 1
x({2}) + x({1,2}) + x({2,3}) + x({1,2,3}) <= 1
x({3}) + x({1,3}) + x({2,3}) + x({1,2,3}) <= 1
x({1}), ..., x({1,2,3}) in {0, 1}
Unless the scores are close to linear, modern MIP solvers on modern hardware should be able to scale to 20 players. If not, there are more complicated techniques.

How to find an algorithm to find a point in a row that has a lower distance with others?

Imagine that we have n city in one row with the same distance and each of them has a population, we want to build a post office, and we want to choose a city that most people have to take a less route to that office, how to find the city?
The user should input the cities number(n) and their population and got the city that the post office should be built.
This is the example that was in the problem and I don't know why it has this result:
6 (number of cities (n))
3 1 0 0 2 2 (populations) ----> 2 (the city number 2 that have a 1 population)
The thing that I'm looking for is an algorithm or a formula to find the city, not the code. Any idea?
If you work out your example, you'll see a simple pattern. Let's say the total distance for index i is x. If we move to index i+1,
All cities in range [0, i] will now become further away from the post office by 1 unit.
All cities in range [i+1, n] will now become closer to the post office by 1 unit.
Using the example you have provided (assuming 0 based indexing):
Let the office be at index 1. Current total distance: 3 + (2*3) + (2*4) = 17
Let's shift it to index 2. Increase in distance for the cities on left of index 2 = 3+1=4. Decrease in distance for cities on the right = 2+2=4.
Simply put, if we move from index i to i+1,
new_distance = old_distance + sum(array[j] for j in range [0,i]) - sum(array[j] for j in range [i+1,n])
To make it more efficient, sum(array[j] for j in range [0,i]) is nothing but prefix sum. You can calculate that in one pass, then solve the distances for each city in another pass. That O(N) time and space complexity.

Maximum Value taken by thief

Consider we have a sacks of gold and thief wants to get the maximum gold. Thief can take the gold to get maximum by,
1) Taking the Gold from contiguous sacks.
2) Thief should take the same amount of gold from all sacks.
N Sacks 1 <= N <= 1000
M quantity of Gold 0 <= M <= 100
Sample Input1:
3 0 5 4 4 4
Output:
16
Explanation:
4 is the minimum amount he can take from the sacks 3 to 6 to get the maximum value of 16.
Sample Input2:
2 4 3 2 1
Output:
8
Explanation:
2 is the minimum amount he can take from the sacks 1 to 4 to get the maximum value of 8.
I approached the problem using subtracting the values from array and taking the transition point from negative to positive, but this doesn't solves the problem.
EDIT: code provided by OP to find the index:
int temp[6];
for(i=1;i<6;i++){
for(j=i-1; j>=0;j--) {
temp[j] = a[j] - a[i];
}
}
for(i=0;i<6;i++){
if(temp[i]>=0) {
index =i;
break;
}
}
The best amount of gold (TBAG) taken from every sack is equal to weight of some sack. Let's put indexes of candidates in a stack in order.
When we meet heavier weight (than stack contains), it definitely continues "good sequence", so we just add its index to the stack.
When we meet lighter weight (than stack top), it breaks some "good sequences" and we can remove heavier candidates from the stack - they will not have chance to be TBAG later. Remove stack top until lighter weight is met, calculate potentially stolen sum during this process.
Note that stack always contains indexes of strictly increasing sequence of weights, so we don't need to consider items before index at the stack top (intermediate AG) in calculation of stolen sum (they will be considered later with another AG value).
for idx in Range(Sacks):
while (not Stack.Empty) and (Sacks[Stack.Peek] >= Sacks[idx]): //smaller sack is met
AG = Sacks[Stack.Pop]
if Stack.Empty then
firstidx = 0
else
firstidx = Stack.Peek + 1
//range_length * smallest_weight_in_range
BestSUM = MaxValue(BestSUM, AG * (idx - firstidx))
Stack.Push(idx)
now check the rest:
repeat while loop without >= condition
Every item is pushed and popped once, so linear time and space complexity.
P.S. I feel that I've ever seen this problem in another formulation...
I see two differents approaches for the moment :
Naive approach: For each pair of indices (i,j) in the array, compute the minimum value m(i,j) of the array in the interval (i,j) and then compute score(i,j) = |j-i+1|*m(i,j). Take then the maximum score over all the pairs (i,j).
-> Complexity of O(n^3).
Less naive approach:
Compute the set of values of the array
For each value, compute the maximum score it can get. For that, you just have to iterate once over all the values of the array. For example, when your sample input is [3 0 5 4 4 4] and the current value you are looking is 3, then it will give you a score of 12. (You'll first find a value of 3 thanks to the first index, and then a score of 12 due to indices from 2 to 5).
Take the maximum over all values found at step 2.
-> Complexity is here O(n*m), since you have to do at most m times the step 2, and the step 2 can be done in O(n).
Maybe there is a better complexity, but I don't have a clue yet.

Combining permutation groups

I am developing a probability analysis program for a board game. As part of an algorithm* I need to calculate the possible permutations of partitions of a number (plus some padding), such that all partition components cannot occupy any position that is lower than the total length of the permutation, in digits, minus the value of the component.
(It is extremely unlikely, however, that the number that will be partitioned will ever be higher than 8, and the length of the permutations will never be higher than 7.)
For instance, say I have the partition of 4, "211", and I want to find the permutations when there is a padding of 2, i.e. length of 5:
0 1 2 3 4 (array indexes)
5 4 3 2 1 (maximum value of partition component that can be allocated to each index)
2 1 1 _ _ (the partition plus 2 empty indexes)
This is represented as an array like so {2,1,1,0,0}
There are 6 permutations when 2 is in the 0 index (4! / 2! 2!), and there are 4 indexes that 2 can occupy (2 cannot be placed into the last index) so overall there are 24 permutations for this case (a 1 can occupy any index).
The output for input "21100":
21100, 21010, 21001, 20110, 20101, 20011
02110, 02101, 02011, 12100, 12010, 12001
00211, 10210, 11200, 10201, 01210, 01201
10021, 01021, 00121, 11020, 10120
01120
Note that this is simply the set of all permutations of "21100" minus those where 2 is in the 4th index. This is a relatively simple case.
The problem can be described as combining n different permutation groups, as the above case can be expressed as the combining of the permutations of x=1 n=4 and those of x=2 n=5, where x is the value count and n is the "space" count.
My difficulty is formulating a method that can obtain all possibilities computationally, and any advice would be greatly appreciated. -Please excuse any muddling of terminology in my question.
*The algorithm answers the following question:
There is a set of n units that are attacked k times. Each
attack has p chance to miss and q (1 - p) chance to damage
a random unit from the set. A unit that is damaged for a second time is destroyed
and is removed from the set.
What is the probability of there being
x undamaged units, y damaged units and z destroyed units after the attacks?
If anyone knows a more direct approach to this problem, please let me know.
I am going to use the algorithm to generate all permutations of the multiset as given in the answer to this question
How to generate all the permutations of a multiset?
and then filter to fit my criteria.

Ranking algorithms to compare "Rankings"

Is there an algorithm that allows to rank items based on the difference of the position of those items in two rankings but also "weighted" with the position, e.g. one Player that goes from position 2->1 should be ranked higher than a player that went from 9->8.
Toy example, I have two lists/ranks:
Rank 1:
Player a
Player b
Player c
Player d
...
Rank 2:
Player d
Player c
Player a
Player b
...
I was thinking to "weight" the ranking difference with the average ranking (or other value), for example, if a player goes from 9->8 the value used to rank will be (9-8)/avg(8,9) = 1/8,5.
What you want seems more or less equivalent to Spearman's rank correlation in non-parametric statistics. It basically sums the squares of the amount_moved (the difference between the old rank and the new rank)
Number your list backwards. Calculate the "value" of moving between positions as the difference of the squares of these numbers.
So if you've got 10 items in your list:
2->1 would be 10^2 - 9^2 = 19
9->8 would be 3^2 - 2^2 = 5.
Hard to tell if this is exactly what you're after without knowing what kind of relative weights you're after. If this doesn't quite suit you, try raising/lowering the exponent to find something that fits.

Resources