Python-2022百度之星——BD202201:洞穴

题目链接:码题集OJ-洞穴 (matiji.net)
怪诞小镇的森林里有一个奇怪的洞穴群。

这个洞穴群包括 n 个洞穴(从 1 到 n 编号)。

每个洞穴中有若干岔路通向其他的洞穴,每条岔路都有一个长度。

日志3上记录了这个洞穴群的一个特点:任意两个洞穴间仅存在一条路径。

此外,日志的主人还在日志3上写下了任意两个洞穴间的距离。

现在小度想要知道这个洞穴群中,哪两个洞穴间存在岔路

格式

输入格式:

多组样例输入,第一行一个整数 T 表示数据组数。

每组数据包括 n+1 行。

第一行一个数字 n 表示洞穴的个数

之后 n 行每行 n 个整数,第 x 行的第 y 个整数 disx,_y_​ 表示洞穴 x 和洞穴 y 间的距离。

(T≤10,1≤n≤100,dis_{x,y}<10_{}^{5}

输出格式:

对于每个样例,首先输出一行一个整数 k,表示洞穴群中存在 k 条岔路。

之后 k 行输出 k 个二元组 (x,y),表示洞穴 x 和洞穴 y 间有一条直接连通的岔路。

请按照(x,y) 递增的顺序输出:即 x 不同时先输出 x 较小的(x,y);x 相同时先输出 y 较小的 (x,y)。

样例 1

输入:

1

5

0 1 2 3 3

1 0 1 2 2

2 1 0 3 3

3 2 3 0 4

3 2 3 4 0

复制

输出:

4

1 2

2 3

2 4

2 5

满足输入距离的洞穴群结构如图。

题解: 

思路:如果题目看不懂,可以把邻接矩阵列出来,如图,将点代入分析发现和Floyd最短路径有些许相似,Floyd算法的关键是寻找加入点后的最短路径:

核心代码:graph[i][j] = min(graph[i][k] + graph[k][j],graph[i][j]) 

 本题的关键也是题目要求是加入点后判断任意两点是否直接连通,题目中任意两洞穴只有一条路径是关键,这也就意味着C->D和C->B->D必须二选一!若C->D==C->B->D,那么路径一定是不符合要求的C->B->D,因为若C->D也成立那么就违反了任意两洞穴只有一条路径。有同学又会问了,会不会是只存在C->D而不是C->B->D呢?答案是否定的,因为看上面的表格会发现C->B->D是确实存在的!因此C->D由于经过了B而不符合题目的直接连通,我们使用flag=False进行短暂的记录。核心代码也就在这里体现,代码如下:

if dis[i][j]==dis[i][k]+dis[k][j]:
    flag=False
    break

具体完整可运行代码为: 

def Floyd():
    T = int(input())
    for t in range(T):
        res = []
        n = int(input())  # 洞穴的个数
        dis = [[0 for _ in range(n)] for _ in range(n)]
        for i in range(n):
            row=list(map(int,input().split()))
            for j in range(n):
                dis[i][j]=row[j]

        for i in range(n):
            for j in range(i+1,n):
                flag=True
                for k in range(n):
                    if k==i or k==j:  #如果不加的话,k=1,计算[1][2]时,[1][2]=[1][1]+[1][2]=[1][2],直接执行flag=False
                                      #简而言之,不加中转点是否等于自身的判断,会导致把自身也当成中转节点
                        continue
                    if dis[i][j]==dis[i][k]+dis[k][j]:
                        flag=False
                        break

                if flag:
                    res.append((i+1,j+1))
        res.sort()
        print(len(res))  # 输出直接连通的岔路的个数
        for item in res:
            print(item[0], item[1])  # 输出结果
Floyd()

这里仍然有几个需要注意的点:

  1. python一定要看缩进,写到最后的排序写道循环外面去了,害我调了半天。。。
  2. append添加元组能过,添加列表(res.append([i+1,j+1]) )不能过,但是输出结果都一样。。。又害我调了半天
  3. j的遍历循环要从i+1,n 因为要避免重复计算,例如计算了[1][2]就不用计算[2][1]了,相当于无向图的Floyd
  4. if k==i or k==j:
        continue
    #如果不加的话,k=1,计算[1][2]时,[1][2]=[1][1]+[1][2]=[1][2],直接执行flag=False
    #任何判断都会经历到k==i or k==j:这一步所以最终结果输出0
    #简而言之,不加中转点是否等于自身的判断,会导致把自身也当成中转节点

第一次在CSDN发布,如有不足和建议请给我留言。 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值