你知道谁知道你想和谁一起参加聚会。假设“知道”是对称的:如果我认识你,你就认识我。你做出了进一步的要求,你希望每个人至少有5个新人在聚会上见面,而且,所以没有人感到太孤立,每个人应该已经知道聚会上至少有5个人。您的原始列表可能不满足这些额外的两个条件,因此您可能需要从邀请列表中删除一些人(或者您可能根本无法参与这些限制)。找到您可以邀请的n个人中最大可能的子集,并满足其他两个要求。对于基本问题,找到一个O(n ^ 3)算法并解释它的顺序和逻辑。
我不是要求答案,而是要求从哪里开始。
答案 0 :(得分:5)
听起来像应用图算法的好地方。
形成人物图表G
。对于n
人,图表中会有n
个节点。如果人i
知道人j
,则链接节点i
和j
。
让G
的第一次迭代调用G_0
。通过G_1
获取G
并取消任何知道太多或太少人的人。 (也就是说,如果i
的链接数为i
或< 5
,则消除此人> n-5
。)
重复此过程,获取G_2
,G_3
最多n
(左右)次迭代,获取G_n
。此图表中剩余的人是您应该邀请的人。
每个n
次传递都需要检查n
人对n
个其他人,因此算法为O(n^3)
。
完成此任务的MATLAB代码(你没有要求它,但我认为它很有趣并且无论如何都写了它):
% 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
示例输出(10人,40个连接,必须至少知道3个人,一定不能知道至少3个人)
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
答案 1 :(得分:1)
我假设信息的表示遵循数据结构:
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
每个人(包括主持人)的详细信息可以存储在“个人[n]”中。
派对的主持人处于第一位置。
我可能需要的子程序:
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
建议的算法:
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
如果你在理解这个算法时遇到任何困难,请告诉我。