首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >大投入城市建设方案超时

大投入城市建设方案超时
EN

Code Review用户
提问于 2019-12-20 00:03:01
回答 1查看 168关注 0票数 6

问题

哈克尔兰国家有n城市连接的m单向公路.这些城市从1n都有编号。最近,政府决定在哈克尔兰建设新城市。您的任务是模拟q事件。事件可以有两种类型,如下所述:

  • 1 x d:在Hackerland建造了一个新的城市n + 1,它与城市x相连。如果是d = 0,新路的方向是从xn + 1。如果是d = 1,新路的方向是从n + 1x
  • 2 x y:如果可以从城市x迁移到城市y,则打印No,否则打印D24

约束

0< n,m <= 50000 0

您可以找到对问题这里的完整描述。

My努力

我试图在这里使用BFS,但是所有的测试用例都失败了,但是由于超时,默认的测试失败了。对于那些测试用例,n >= 4000. m >= 20000

代码

代码语言:javascript
复制
from collections import defaultdict, deque

n, m = map(int, input().split())

adjacentNodes = defaultdict(set)
for _ in range(m):
    u, v = map(int, input().split())
    adjacentNodes[u].add(v)

q = int(input())
for _ in range(q):
    c, x, d = map(int, input().split())

    if c == 1:
        n += 1
        y = n

        if d == 0:
            adjacentNodes[x].add(y)
        else:
            adjacentNodes[y].add(x)
    else:
        y = d
        visited = set()
        current = deque()
        current.append(x)
        answer = "No"
        while current:
            parent = current.popleft()
            if parent == y:
                answer = "Yes"
                break
            if parent in adjacentNodes:    
                for i in adjacentNodes[parent]:
                    if i not in visited:
                        visited.add(i)
                        current.append(i)
        print (answer) 

问题

有没有人建议如何优化解决方案?

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-12-25 22:13:45

这是一个艰难的过程,但我设法解决了它,并通过了所有的测试用例。以下是要点。

首先Build一个完全有向图

保存查询,因为可以使用它们的100,000,并且首先构建一个完整的图,然后在上面运行所有的查询,效率更高。

Find所有强连接组件

在图中找到所有强连通的组件,然后基于它们构建一个可达映射。它具有较低的空间复杂度,因为每个强组件都可以由单个节点表示,因此我们不需要为每个节点设置一个可达性集,而只需要为其代表设置一个可达性集。

用于查找可达集的Use DFS

修改DFS,以便在运行DFS之后,每个连接组件都包含其他可访问的连接组件的代表(所谓的低链路节点)。但是,如果一个低链路节点是可访问的,那么来自其连接组件的任何节点也是可访问的。

有效存储强组件Use内存

创建一个(n + 1)整数值数组,其中n -图中的节点数。索引标识图中的一个节点和一个值-所有连接的组件(低链路节点)可从图中到达。值可以有最多n + 1二进制数字(如果所有节点都可以从当前节点到达)。

<#>Increase递归限制

由于节点数可以到达50000,因此必须将递归调用堆栈设置为此值。

Solution代码

代码语言:javascript
复制
from collections import defaultdict, deque
import sys

sys.setrecursionlimit(50001)

n, m = map(int, input().split())
adjacentNodes = defaultdict(set)
for _ in range(m):
    u, v = map(int, input().split())
    adjacentNodes[u].add(v)

q = int(input())
# read all queries first
queries = []
for i in range(q):
    c, x, d = map(int, input().split())
    if c == 1:
        n += 1
        y = n
        if d == 0:
            adjacentNodes[x].add(y)
        else:
            adjacentNodes[y].add(x)
    else:
        y = d
        queries.append((x, y))

# each node with number i corresponds to 2^i
nodeDpPosition = {i: (1 << i) for i in range(n + 1)}
# Implementation using the Tarjan algorithm
# https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
def findAllConnectedComponents(edges):
    connectedComponents = [0 for _ in range(n + 1)]
    index = {'value' : 0}
    # map node to its connected component low link node
    connectedComponentLink = {}

    nodeStack = deque()
    indices = [-1] * (n + 1)
    lowLinks = [0] * (n + 1)
    onStack = [False] * (n + 1)

    def connectedComponent(node):
        indices[node] = index['value']
        lowLinks[node] = index['value']
        index['value'] += 1
        nodeStack.append(node)
        onStack[node] = True

        for adjacentNode in edges[node]:
            if indices[adjacentNode] < 0:
                connectedComponent(adjacentNode)
                lowLinks[node] = min(lowLinks[node], lowLinks[adjacentNode])
            elif onStack[adjacentNode]:
                # we have reached the previously visited node or come back in the call stack
                lowLinks[node] = min(lowLinks[node], indices[adjacentNode])

        if lowLinks[node] == indices[node]:
            while nodeStack:
                current = nodeStack.pop()
                connectedComponentLink[current] = node
                onStack[current] = False
                connectedComponents[node] |= nodeDpPosition[current]

                if current == node:
                    break

    for i in range(1, n + 1):
        if indices[i] < 0:
            connectedComponent(i)

    return (connectedComponents, connectedComponentLink)

connectedComponents, connectedComponentLink = findAllConnectedComponents(adjacentNodes)

def advancedDfs(node):
    lowLinkNode = connectedComponentLink[node]

    neighbours = adjacentNodes.get(node)
    if neighbours is not None:
        for neighbour in neighbours:
            lowLinkNeighbourNode = connectedComponentLink[neighbour]
            if (connectedComponents[lowLinkNode] & nodeDpPosition[lowLinkNeighbourNode]) == 0:
                connectedComponents[lowLinkNode] |= nodeDpPosition[lowLinkNeighbourNode]
                advancedDfs(lowLinkNeighbourNode)

            connectedComponents[lowLinkNode] |= connectedComponents[lowLinkNeighbourNode]

for i in range(1, n + 1):
    advancedDfs(i)

for query in queries:
     x, y = query
     lowLinkXNode = connectedComponentLink[x]
     lowLinkYNode = connectedComponentLink[y]
     if connectedComponents[lowLinkXNode] & nodeDpPosition[lowLinkYNode]:
         print ("Yes")
     else:
         print ("No")
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/234359

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档