我有一种算法可以解决给定输入中的“受影响的人”。 我必须解决受影响者的名单。人用数字表示,并且两个人在给定的时间N处相互交互。如果其中一个人受到影响,另一个人也将受到影响。
首先,给出 N(人数)和M(互动总数)。 然后在 M 行中给出(P1 P2时间)。
例如, 5 5
2 3 1
1 2 2
3 4 2
1 3 3
2 5 4
给出。
这意味着有5个人,他们有5次互动,其后是5行,分别表示在时间1的人2和3开会,在时间2的1和2会议,在时间2的3和4会议,等等。 。(可能无法订购)。
开始时,第1个人总是被感染。
因此,在时间2,人 1 和 2 相遇,使人 2 被感染, 人 1 和 3 在时间3相遇,使人 3 被感染, 最后,在时间4,人 2 和 5 相遇,使人 5 被感染。
这使人最终被 1、2、3、5 感染。
互动是按时间发生的,并且可以同时发生多种互动,如果是这种情况,则必须考虑大多数人 受到影响。
例如,如果第1个人和第3个人被感染,并且以(4 6 3)(3 6 3)作为输入,则必须首先计算(3 6 3)才能使第6个人受到感染,第4个人受到感染好吧。
为解决这个问题,我创建了这个算法,它的运行时间很糟糕,我需要帮助优化该算法。
inputs = input()
peopleNum = int(inputs.split()[0])
times = int(inputs.split()[1])
peopleMeet = {}
affectedPeople = [1]
for i in range(times):
occur = input()
person1 = int(occur.split()[0])
person2 = int(occur.split()[1])
time = int(occur.split()[2])
if not time in peopleMeet:
peopleMeet[time] = [(person1, person2)]
else:
for occur in range(len(peopleMeet[time])):
if set(peopleMeet[time][occur]) & set((person1,person2)):
peopleMeet[time][occur] = peopleMeet[time][occur] + ((person1,person2,))
break
if occur == (len(peopleMeet[time]) - 1):
peopleMeet[time].append((person1,person2))
for time in sorted(peopleMeet):
for occur in peopleMeet[time]:
if set(affectedPeople) & set(occur):
affectedPeople.extend(list(occur))
print(' '.join([str(x) for x in set(affectedPeople)]))
我对堆栈溢出很陌生,而且我不习惯格式和发布准则,所以对不起我很抱歉。并先谢谢您。
答案 0 :(得分:2)
伪代码:
affectedPeople = bool array of size N + 1, initialized at false
affectedPeople[1] = True
sort the interactions based on time
iterate interactions and group them by time
for each group x:
create a graph with interactions from that group as edges
do a dfs on each affectedPeople present on these interactions. All the reached nodes will be affected
add these nodes to affectedPeople (set them to True)
count amount of i with affectedPeople[i] = True
答案 1 :(得分:1)
解决该问题的另一种方法是使用union-find
算法,该算法的运行时复杂度为O(n*log(n))
。这个想法很简单:
根据时间参数以升序对给定输入进行排序。
按时间对交互进行分组,对于每个组,对交互进行迭代,并将参与其中的人员合并在一起。
在联合操作中,如果配方组被感染,则保留信息(请参阅代码以更好地理解)。
对于参与此组交互的每个人,请检查他是否属于受感染的组,并将其也标记为受感染。
将该组中的人员的工会发现状态重置为原始状态,以便我们可以重新处理另一个组,同时保留有关当前感染者的信息。
这是相同的代码:
MAX_N = 1000
parent = list(range(MAX_N))
infected = [False] * MAX_N
def find(x):
if x == parent[x]: return x
parent[x] = find(parent[x])
return parent[x]
def union(x, y):
parent_x = find(x)
parent_y = find(y)
# If either of the two clusters we're joining is infected
# Infect the combined cluster as well
infected[parent_y] = infected[parent_x] or infected[parent_y]
parent[parent_x] = parent_y
def solve(inputs):
infected[1] = True
# Sort the input by the time parameter
inputs.sort(key=lambda x: x[2])
answer_set = set()
i = 0
while i < len(inputs):
persons = set()
cur_time = inputs[i][2]
# Iterate over interactions belonging to the same group i.e. same time
while i < len(inputs) and inputs[i][2] == cur_time:
person_x = inputs[i][0]
person_y = inputs[i][1]
persons.add(person_x)
persons.add(person_y)
# Union the people involed in the interaction
union(person_x, person_y)
i += 1
for person in persons:
group = find(person)
# If the person belongs to an infected group, he's infected as well
if infected[group]:
infected[person] = True
answer_set.add(person)
# Reset the union-find state as we move to the next time step
for person in persons:
parent[person] = person
return answer_set
print (solve([[2, 3, 1], [1, 2, 2], [1, 3, 3], [2, 5, 4], [3, 4, 2]]))
答案 2 :(得分:0)
查看代码中的注释:
DATA = [[2, 3, 1], [1, 2, 2], [3, 4, 2], [1, 3, 3], [2, 5, 4]]
# status contains the contamination status for each people in the dataset
# At the begining we will have only [1] contaminated so:
# {1: True, 2: False, 3: False, 4: False, 5: False}
people_status = {}
for people_id in set(x[0] for x in DATA).union(x[1] for x in DATA):
people_status[people_id] = people_id == 1
# meeting contains DATA grouped by time so with this dataset we will have:
# {1: [[2, 3]], 2: [[1, 2], [3, 4]], 3: [[1, 3]], 4: [[2, 5]]}
meeting = {}
for x in DATA:
if x[2] in meeting:
meeting[x[2]].append(x[:2])
else:
meeting[x[2]] = [x[:2]]
# now we just have to update people_status while time evolve
for time in sorted(meeting.keys()):
while True:
status_changed = False
for couple in meeting[time]:
if people_status[couple[0]] != people_status[couple[1]]:
status_changed = True
people_status[couple[0]] = people_status[couple[1]] = True
if not status_changed:
break
# create the list of infected people
infected_people = []
for people_id, status in people_status.items():
if status:
infected_people.append(people_id)
print(infected_people)
将打印结果:
[1, 2, 3, 5]