8

So I am doing an exercise in which there are $n$ people who are either knight or rogue, more than $\frac{n}{2}$ are knights. You are a princess and would like to marry a knight and do not want to accidentally marry a rogue.

You can select any pair of the $n$ people to make them point out each other's identity. The knight will always tell the truth, while the rogue may or may not. If there are two rogues being interrogated, they may say each other is good to deceive you.

How can I design an efficient algorithm for the princess to find out a knight?

My attempt:

So I can pit one person j against the other $n-1$ persons to find out if j is knight or rogue. There are $k > \frac{n}{2}$ knights, and $r \leq \frac{n}{2}-1$ rogues.

If j is a knight, then he will be pitted against $k-1$ other knights and $r$ rogues. So there are $\geq \frac{n}{2}$ cases in which both say the other person is knight, and there will be $\leq \frac{n}{2} - 1$ cases that at least 1 person is accused of being a rogue.

If j is a rogue, then j will be pitted against $k$ knights and $r-1$ other rogues, resulting in $k$ cases of at least one rogue accusation, and at most $r-1$ cases of both being said to be knight (as the 2 rogues may or may not team up to deceive the princess).

Looking at the distribution of cases "both say the other is knight" and "at least one rogue accusation", we can identity if the person being examined is a knight or rogue.

If I am to brute force, then I can do $O(n)$ queries for each person, giving $O(n^2)$ time.

But I am uncertain how to do divide and conquer here.

I can eliminate dividing naively into $\frac{n}{2}$ sizes, because the distribution of knights and rogues will no longer follow the initial more than $\frac{n}{2}$ knights.

One idea I have is, initially pick one person j and do the pairing with $n-1$ others to see if he is knight or rogue. If he is knight then we're done. If he is rogue, then we can know which in the previous results must be rogues. The other person in the cases of "both knights" must be rogue. Also, in the cases of "one knight one rogue", those who say j is knight are lying and must be rogues.

So we select the ones who are either a rogue that didn't lie, or a knight, and recurse on them.

The worst case would be that every rogue does not lie.

What are you thoughts on this? Thank you!

AlgoManiac
  • 83
  • 1
  • 4

5 Answers5

10

An efficient algorithm using stack

  1. Initialize an empty stack.
  2. For each person $p$ in the given people:
    • If the stack is empty, push $p$ to the stack.
    • Otherwise, pit $p$ against the person at the top of the stack.
      • If both say the other one is a knight, either both are knights or both are rogues. Push $p$ to the stack.
      • Otherwise, at least one of them is a rogue. Pop the stack once.
  3. Return the person at the top of the stack.

The time-complexity of the algorithm is $O(n)$.
The space-complexity of the algorithm is $O(1)$ if we can reuse the input array as a stack.

Two Exercises

Exercise 1 (easy). Explain why all people in stack at the end are knights.

Exercise 2 (easy). Suppose the number of knights is equal to the number of rogues instead. Show that it is impossible to find a knight for sure in the worst case.

John L.
  • 39,205
  • 4
  • 34
  • 93
8

Our princess proceeds as follows:

  • she asks her suitors to form up on a line
  • starting from the left, she asks each person about the virtue of their neighbour (and vice versa)
    • if there is an accusation of rogueness
      • she sends both of them away
      • if there are people on either side of the gap, they are now neighbors. She will investigate them next as she continues her walk along the line.
    • everyone to her left is of equal virtue. If that's more than half of the people remaining, these must be the knights, and she can pick any of them

It easy to see that this process eliminates at least as many rogues as knights, thereby maintaining the honest majority.

It also easy to see that this process is efficient: With every question, the number of people to the right of the princess decreases by one. The princess will therefore ask at most n-1 questions.

meriton
  • 529
  • 3
  • 7
3

This can be solved efficiently with the Boyer-Moore majority algorithm. Everyone casts a vote on the candidate currently occupying the hot seat. When the count reaches zero, the candidate is evicted and the next one takes the seat. The algorithm takes constant space and N-1 tests maximum.

def find_knight(candidates):
    victor = None
    count = 0
    for candidate in candidates:
        # Take the seat if empty. Set counter to 1 because
        # the candidate presumably supports himself.
        if count = 0:
            victor = candidate
            count = 1
        # Otherwise upvote or downvote the sitting candidate.
        elif supports(candidate, victor):
            count += 1
        else:
            count -= 1
    return victor
Rainer P.
  • 862
  • 5
  • 9
2

Here is a divide-and-conquer algorithm that performs 2N tests maximum. At each stage we perform N tests and eliminate at least half of the candidates.

def find_knight(candidates):
    # No solution if there are no candidates.
    if len(candidates) == 0:
        return None
    # Set one aside if there is an odd number of candidates.
    if len(candidates) % 2:
        unpaired = candidates.pop()
    # Divide the candidates into N/2 pairs and ask them about each 
    # other. Eliminate both if they accuse each other, else keep one.
    remaining = []
    for i in range(len(candidates) // 2):
        a = candidates[2*i]
        b = candidates[2*i+1]
        if supports(a, b) and supports(b, a):
            remaining.append(a)
    # Recursive call, might return no solution if we
    # set aside a real knight (and only then).
    solution = find_knight(remaining)
    if solution is None:
        solution = unpaired
    return solution

To prove correctness, prove that:

  1. If knights make up at least half of the candidates before elimination, this also holds after elimination.
  2. If there is an odd number of candidates after elimination, there are strictly more knights.
  3. If we set the unpaired candidate aside, knights still make up at least half of the remaining candidates.
  4. If there are equally many knights and rogue, there might be no solution.
  5. If there is no solution, the one we set aside must have been a knight.
Rainer P.
  • 862
  • 5
  • 9
0

Given are m people, all either knight or rogue, and more knights than rogues. We want to find one knight (one is enough). We want to do this with the minimum amount of questions, and the rogues will try to make us ask as many questions as possible.

First an observation: If the number of knights and rogues is the same, then we can't determine a knight by asking people whether others are knights or rogues. That's because the rogues will try to hide their identity by always lying about someone else's identity; they will always claim that another knight is a rogue, and that another rogue is a knight. This means, if we changed every single person's identity from knight to rogue or from rogue to knight simultaneously, then we would get the exact same answers, but whoever we picked as a knight would now be a rogue. So it is necessary that we have more knights than rogues and must not do anything that changes things. And it means that if only two persons are left, they are both knights (a rogue + more knights than rogues requires at least three).

Assume m = 2n+1. There are at least n+1 knights. Let L be the last person. We ask the first 2n whether L is a knight. A knight will get at least n "yes" votes (n votes from the other n knights, and possibly votes from one or more rogues). A rogue will get less than n "yes" votes, because the n+1 knights will all say L is a rogue. So once we got n "yes" votes, L is a knight and we are done. If we get fewer than n "yes" votes, then L is a rogue and can be removed. At that point we can also remove everyone who claimed that L was a knight, because they lied and must be rogues.

How will rogues vote so we need to ask the largest amount of questions? If L is a knight, we know this will be found, as soon as n knights have been asked, or earlier if some rogues claim he is a knight. So the rogues will all claim L is a rogue, delaying the decision until we asked the n-th knight.

If L is a rogue, that will also be found out, but it will not end the problem. We know L is rogue as soon as n+1 people claimed he is rogue. But everyone who claims L is a knight will out himself as a rogue. So best case, we know L is rogue after asking n+1 people who claim this. If k rogues claim L is a knight, we need to ask n+1+k people to know L is rogue, but k people will now be known to be rogue and can be removed. That gives us additional information that could be used in the next round: We will know that the number of knights exceeds the rogues by k+1, which makes it easier. The rogues will avoid giving us the extra information, so they will all claim L is rogue and L is identified after asking n+1 people. We then have an even m.

We know have 2n persons. It was suggested to line them all up and ask each what his neighbour is, and if anyone says the neighbour is rogue, then one of them must be rogue and we remove them both from the game. However, the rogues don't like this, so they will always claim the next person is a knight. If we have n knights followed by n rogues, only one person will claim the next one in the line is a rogue. Instead we arrange them in n pairs and ask each in the pair what the other is.

If a pair is a knight and a rogue, one or both will answer "rogue", and we know that one is a rogue - we remove both. Otherwise, two knights or two rogues will both claim that the other is a knight. Once done, we have k pairs left over both claiming they are both knights, but they will both be knights, or both rogues.

We remove one from each pair. We will have half the knights and half the rogues of before, so again more knights than rogues. Unless the total is 2 or less, we ask them all again. Here the worst case is that all pairs are either both knights or both rogues, so in 2n questions we have reduced the problem to finding a knight amount n people using n steps.

So in the worst case, we need 3n questions to remove the number of candidates from 2n to n. If we pick the pairs at random, there is a 50% chance that there is exactly one rogue in the pair, and a 25% that we know there is a rogue after the first question. So on average the number of people gets reduced to n/2 (n people in pairs of two knights or two rogues, and half removed later) after 2.75 questions; but then rogues will try to make sure that an the number of people remaining is odd. If there are say 100 pairs of two knights or two rogues, the last pair of two rogues will claim they are both rogues - leaving 99 instead of 100 people.

gnasher729
  • 32,238
  • 36
  • 56