问题
Can someone help me solve this?
We recently held an election for 3 positions.
There were 6 candidates.
Each member could cast 3 votes but could not vote for the same person more than once.
134 ballots were cast. (402 total votes)
The final tally was
result = {a:91, b:66, c:63, d:63, e:60, f:59}
I can easily determine the 20 possible unique ballots cast
result.keys.combination(3).to_a
But obviously given the number of possible combinations brute force would be impossibly time consuming so I am hoping someone can provide an algorithm to solve this practically.
I am trying to find a reasonably efficient way to determine a single possible tally of ballots but if you can provide multiple or all possible tallies that would be amazing.
回答1:
If anybody has more than one third of the possible votes, or if the number of votes is not a multiple of three, there is no possible answer.
If there are at least three votes left, and nobody has more than one third of the possible votes, decide on a ballot paper that gives the top three candidates one vote each and reduce their totals by one.
This process stops either with all votes accounted for or with somebody having more than one third of the vote. I think the worst case for this is votes (N+1, N, N, N) where you go to (N, N-1, N-1, N) where the count not decremented gains a little but does not reach one third, so I think you can continue this process to account for all votes cast.
There are obvious many different equivalent counts. Any pair of actions that do not overlap in two candidates has at least one possible alternative interpretation. One way to generate multiple solutions would be to chose possible ballots at random subject only to the constraint that no sum ever gets to more than one third of the possible votes left. Another would be to rearrange answers at random and follow https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm (although I have not proved that any particular set of small rearrangements makes the set of possible solutions connected)
回答2:
Lets think about simpler thing, for example canapé. You have N
small slices of bread and M
ingredients (Mi
pieces each).
You have to create N
canapes with unique ingredients. Obviously, this is impossible if there is Mi > N
.
reasonably efficient way to determine a single possible tally of ballots
Arrange the bread slices in a line. Take the first ingredient and spread it all out, starting with the first slice of bread. Take the second ingredient and so on until you reach the last piece of bread. Return to the first slice of bread and continue to lay on top. Continue until you run out of ingredients.
require 'set'
result = {a: 91, b: 66, c: 63, d: 63, e: 60, f: 59}
BALLOTS = 134
if (result.values.any? { |v| v > BALLOTS }) || (result.values.sum % BALLOTS != 0)
raise 'Unfair election!'
end
ballots = BALLOTS.times.map { Set.new }
i = 0
result.each do |candidate, votes|
votes.times do
ballots[i % BALLOTS] << candidate
i += 1
end
end
puts "Do all of them have 3 unique votes? #{ballots.all? { |b| b.size == 3 }}"
Obviously, it's O(∑Mi)
where ∑Mi
is 402 (your "total votes"). I don't think there is a faster way.
but if you can provide multiple or all possible tallies
You can change the ingredients order. In your case there are 6! = 720
ways to fill the ballots. And I found that 60 of them are unique.
There is different amount of unique tallies for the different results. There are only 10 unique ways for result = {a: 67, b: 67, c: 67, d: 67, e: 67, f: 67}
for example.
Changing start position (i = start # instead of 0
) does not provide new unique ways.
回答3:
Although one can may be able to find a feasible solution for a given result
using a heuristic algorithm, there is no assurance of that as it an NP-hard problem. It could be formulated as an integer linear program (ILP). In principle, ILP software will identify a feasible solution or report that no feasible solution exists. I say "in principle" because the problem may well be unsolvable in the time available.
This ILP problem has 20x6 = 120 non-negative, integer-valued variables and 6 constraints.
The variables are:
ni : the number of times ballot i is cast, i = 1,2,...,20
#<Set: {1, 3, 5}>
is an example of one of the 20 ballots.
There are two types of known constants:
aij : equal to 1 if ballot i contains a vote for candidate j, i = 1,2,...,20, j = 1,...,6, else zero
vj : the number of votes candidate j is to receive, j = 1,...,6
The constraints are as follows.
∑iniaij = vj, j = 1,...,6
ni >= 0 and integer-valued, i = 1,2,...,20
The first set of contraints ensures that each candidate receives the specified number of votes. The second set of contraints is implicit in ILP's.
ILP's also have objective functions to be maximized or minimimized, subject to the constraints. Here only a feasible solution is desired so the objective function might be expressed as
max 0x1
or something equivalent.
回答4:
I can't believe I was so stuck on this but thank you @mcdowella for shaking me free of it.
We can just keep randomly shuffling and shifting the lists until we get a list where each group contains exactly 3 elements. It is definitely brute force but for a single result it is reasonably efficient (albeit unpredictable)
result = {a: 91, b: 66, c: 63, d: 63, e: 60, f: 59}
votes = result.map { |candidate, count| [candidate] * count }
def build_election(arr)
134.times.map do |x|
arr.shuffle.select {|a| !a.empty? }.first(3).map do |s|
s.pop
end
end
end
@a = build_election(votes.map(&:dup)) until @a&.all? {|s| s.size == 3}
来源:https://stackoverflow.com/questions/64180561/algorithm-ballots-cast-in-an-election