You know who knows who among n people that you would like to have come to a party. Assume "knows" is symmetric: If I know you, you know me. You make further requirements that you want each person to have at least 5 new people to meet at the party, and also, so nobody feels too isolated, each person should already know at least 5 people at the party. Your original list may not satisfy these extra two conditions, so you may need to eliminate some people from the invitation list (or maybe you cannot have a party at all with these restrictions). Find a largest possible subset of the n people that you could invite and satisfy the the other two requirements. For the basic problem, find an O(n^3) algorithm and explain its order and its logic.
I ask not for the answer, but for guidance on where to start.
Sounds like a good place to apply a graph algorithm.
Form a graph of people, G
. For n
people there will be n
nodes in the graph. Link nodes i
and j
if person i
knows person j
.
Let the first iteration of G
be called G_0
. Obtain G_1
by making a pass through G
and eliminate any person who knows too many or too few people. (That is, eliminate person i
if the number of links to i
is < 5
or > n-5
.)
Repeat the process, obtaining G_2
, G_3
up to a maximum of n
(or so) iterations, obtaining G_n
. The people remaining in this graph are the people you should invite.
Each of the n
passes requires a check of n
people against n
other people, so the algorithm is O(n^3)
.
MATLAB code to accomplish this (you didn't ask for it, but I thought it was interesting and wrote it anyway):
% number of people on original list
N = 10
% number of connections to (attempt) to generate
% may include self-links (i,i) or duplicates
M = 40
% threshold for "too few" friends
p = 3
% threshold for "too many" friends
q = 3
% Generate connections at random
G = zeros(N);
for k = 1:M
i = randi(N);
j = randi(N);
G(i,j) = 1;
G(j,i) = 1;
end
% define people to not be their own friends
for i = 1:N
G(i,i) = 0;
end
% make a copy for future comparison to final G
G_orig = G
% '1' means invited, '0' means not invited
invited = ones(1,N);
% make N passes over graph
for k = 1:N
% number of people still on the candidate list
n = sum(invited);
% inspect the i'th person
for i = 1:N
people_known = sum(G(i,:));
if invited(i) == 1 && ((people_known < p) || (people_known > n-q))
fprintf('Person %i was eliminated. (He knew %i of the %i invitees.)\n',i,people_known,n);
invited(i) = 0;
G(i,:) = zeros(1,N);
G(:,i) = zeros(1,N);
end
end
end
fprintf('\n\nFinal connection graph')
G
disp 'People to invite:'
invited
disp 'Total invitees:'
n
Sample output (10 people, 40 connections, must know at least 3 people, must not know at least 3 people)
G_orig =
0 0 1 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 1
1 0 0 1 1 1 0 0 0 1
1 0 1 0 0 1 0 1 1 0
0 0 1 0 0 0 1 0 1 1
0 1 1 1 0 0 0 1 0 1
0 0 0 0 1 0 0 0 1 0
0 0 0 1 0 1 0 0 0 1
1 0 0 1 1 0 1 0 0 1
0 1 1 0 1 1 0 1 1 0
Person 2 was eliminated. (He knew 2 of the 10 invitees.)
Person 7 was eliminated. (He knew 2 of the 10 invitees.)
Final connection graph
G =
0 0 1 1 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0
1 0 0 1 1 1 0 0 0 1
1 0 1 0 0 1 0 1 1 0
0 0 1 0 0 0 0 0 1 1
0 0 1 1 0 0 0 1 0 1
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 1
1 0 0 1 1 0 0 0 0 1
0 0 1 0 1 1 0 1 1 0
People to invite:
invited =
1 0 1 1 1 1 0 1 1 1
Total invitees:
n =
8
I am assuming following data structure for the representation of the information:
Person
name : string, if this is empty or null, the person isnt not invited to party
knows: array of pointers to type Person. Indicates whom this person 'knows'
knows_cnt : size of "knows" array
Details of everyone (including host) can be stored in "Person individuals[n]".
The host of party being at first position.
A subroutine that i might need for algo:
RemovePerson (individuals, n, i)
// removes i'th person from individuals an array of n persons
set individuals[i].name to empty so that this person is discarded
For j from 1 to individuals[i].knows_cnt
// as knows is symmetric, we can get the persons' contact right away
Person contact = individuals[i].knows[j]
if contact.name is empty,
continue
modify contact.knows to remove i'th person.
modify corresponding contact.knows_cnt
end for
end RemovePerson
The proposed algorithm:
change = true
invitees = n
while [change == true]
change = false
for i = 2 to n do
// start from 2 to prevent the host getting discarded due to condition #2
if individuals[i].name is empty,
continue
// condition #1,
// check if the person knows atleast 5 people
if individuals[i].knows_cnt < 5
change = true
invitees = invitees - 1
RemovePerson(individuals, n, i)
// condition #2
// check to find out if the person will get to know 5 new people
if (invitees - individuals[i].knows_cnt) < 5
change = true
invitees = invitees - 1
RemovePerson(individuals, n, i)
end for
end while
return invitees
Let me know if you face any difficulty in understanding this algo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With