[算法]管道网络

管道网络

问题地址

题目描述

Description

Every house in the colony has at most one pipe going into it and at most one pipe going out of it. Tanks and taps are to be installed in a manner such that every house with one outgoing pipe but no incoming pipe gets a tank installed on its roof and every house with only an incoming pipe and no outgoing pipe gets a tap. Find the efficient way for the construction of the network of pipes.

Input

The first line contains an integer T denoting the number of test cases. For each test case, the first line contains two integer n & p denoting the number of houses and number of pipes respectively. Next, p lines contain 3 integer inputs a, b & d, d denoting the diameter of the pipe from the house a to house b.Constraints:1<=T<=50,1<=n<=20,1<=p<=50,1<=a, b<=20,1<=d<=100

Output

For each test case, the output is the number of pairs of tanks and taps installed i.e n followed by n lines that contain three integers: house number of tank, house number of tap and the minimum diameter of pipe between them.

Sample Input 1

1
9 6
7 4 98
5 9 72
4 6 10
2 8 22
9 7 17
3 1 66

Sample Output 1

3
2 8 22
3 1 66
5 6 10
题目解析
  1. 9,6分别代表水管数量和房屋数量
  2. 接下来6行代表6根水管的连接情况,可以想象成边,其中每行第一个数和第二个数分别是边的起始点和终点,也就是房屋的编号,即每行代表了每两个房屋之间的水管直径
  3. 这样我们就可以构建出一个图,图中有哪些房屋连接,哪些房屋没有连接
  4. 按照房屋编号由小到大输出所有连通路径上的最小水管直径即可,
思路解析

思路一
这种方式感觉在有交叉的时候可能会不对,但是可以过

一种就是先找到每个连通路径的开头的房屋,遍历开头房屋,将房屋进行连接,记录连通路径上的最小直径

思路一来自博客,以下文字和图片转自链接博客

img

把上面的输入输出用例画出来就是水管的连接图,箭头连接的是不同的人家,箭头上面的数字是水管的直径,我们需要在没有输入水管的人家安装tank,在没有输出的人家安装tap,所以需要安装的是5 -> 6, 2 -> 8, 3 -> 1,至于安装在它们之间的最小水管大小,就是连通路径上的最小水管直径。比如5 -> 6连通路径上最小的直径是10,因此最后结果就是10。

解题思路:

  1. 找到所有的起点(5, 2, 3)

    可以先记录所有路径的起点,和终点,最后用起点减去终点,就能找到所有真实的起点。

  2. 从起点开始,找出下一条路径,直到没有下一条路径结束,记录结束的点(与上面对应的是6, 8, 1)

    记录从起点到终点的路径中,需要记录管道直径的最小值,最后输出

作者:loick

链接:https://www.jianshu.com/p/5f19f02891ad

思路二

一种是使用图的深度遍历,找到所有路径,并记录出最小水管直径

代码实现

思路1(python)

代码思路来自上述博客,加上了部分注释

if __name__ == '__main__':
    for _ in range(int(input())):
        _, t = map(int, input().strip().split())
        pairs = [tuple(map(int, input().strip().split())) for _ in range(t)]  # 打包成元组
        # 初始化
        link, vals = {}, {}
        for l, r, v in pairs:
            link[l] = r  # key:起始点 val:终止点
            vals[(l, r)] = v  # key:(起始点,终止点) val:值
        # 求起点人家:
        start_arr = set(link.keys()) - set(link.values())
        # 根据起点人家连接管道
        ans = []
        for s in start_arr:
            e = link[s]  # 初始化终点
            val = vals[s, e]  # 初始化该水管的直径
            while e in link:  # 若e在link的key中,证明有下一户人家
                val = min(val, vals[e, link[e]])  # 将直径更新为较小的,注意顺序
                e = link[e]  # 将终点更新为该户人家的终点
            ans.append((s, e, val))  # 将起点,终点,水管值添加到答案中
        ans = sorted(ans)  # 答案的顺序是由人家的有小到大的顺序排列的
        print(len(ans))
        for p in ans:
            print(*p)

思路二: 深度遍历(java)

(粘贴自开头连接)

// Java program to find efficient 
// solution for the network 
import java.util.*; 
  
class Main { 
      
    // number of houses and number 
    // of pipes 
    static int n, p; 
  
    // Array rd stores the  
    // ending vertex of pipe 
    static int rd[] = new int[1100]; 
  
    // Array wd stores the value  
    // of diameters between two pipes 
    static int wt[] = new int[1100]; 
  
    // Array cd stores the  
    // starting end of pipe 
    static int cd[] = new int[1100]; 
  
    // arraylist a, b, c are used 
    // to store the final output 
    static List <Integer> a =  
              new ArrayList<Integer>(); 
                
    static List <Integer> b =  
              new ArrayList<Integer>(); 
                
    static List <Integer> c =  
              new ArrayList<Integer>(); 
      
    static int ans; 
      
    static int dfs(int w) 
    { 
        if (cd[w] == 0) 
            return w; 
        if (wt[w] < ans) 
            ans = wt[w]; 
              
        return dfs(cd[w]); 
    } 
  
    // Function to perform calculations. 
    static void solve(int arr[][]) 
    { 
        int i = 0; 
      
        while (i < p) 
        { 
              
            int q = arr[i][0]; 
            int h = arr[i][1]; 
            int t = arr[i][2]; 
              
            cd[q] = h; 
            wt[q] = t; 
            rd[h] = q; 
            i++; 
        } 
          
        a=new ArrayList<Integer>(); 
        b=new ArrayList<Integer>(); 
        c=new ArrayList<Integer>(); 
          
        for (int j = 1; j <= n; ++j) 
          
            /*If a pipe has no ending vertex  
            but has starting vertex i.e is  
            an outgoing pipe then we need  
            to start DFS with this vertex.*/
            if (rd[j] == 0 && cd[j]>0) { 
                ans = 1000000000; 
                int w = dfs(j); 
                  
                // We put the details of 
                // component in final output 
                // array 
                a.add(j); 
                b.add(w); 
                c.add(ans); 
            } 
              
        System.out.println(a.size()); 
          
        for (int j = 0; j < a.size(); ++j) 
            System.out.println(a.get(j) + " " 
                + b.get(j) + " " + c.get(j)); 
    } 
  
    // main function 
    public static void main(String args[]) 
    { 
        n = 9; 
        p = 6; 
          
        // set the value of the araray  
        // to zero 
        for(int i = 0; i < 1100; i++) 
            rd[i] = cd[i] = wt[i] = 0; 
          
        int arr[][] = { { 7, 4, 98 }, 
                        { 5, 9, 72 }, 
                        { 4, 6, 10 }, 
                        { 2, 8, 22 }, 
                        { 9, 7, 17 }, 
                        { 3, 1, 66 } }; 
        solve(arr); 
    } 
} 
  
// This code is contributed by Arnab Kundu
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值