java 无向连通图算法

如果对你有帮助记得素质三连~

转载请注明出处~

https://blog.csdn.net/L_Open2021/article/details/123428115

算法功能(最底部代码只有实现此功能的算法代码)

给定点,边,起始点,终止点,和各个点的开关状态(只需要所有关闭的阀门即可)

返回找出的所有从起点到终点的所有通路,可以为空或多条

结合算法实现的需求及实现

我们要计算水管的流动效果方向等,下面算法是为了计算所有连通的管路,可以将阀门看作每一个点,阀门和阀门之间看作一个边.

在实际操作中,我们把创建了点(阀门)和边(管路)的对应表,

边(管路)表中设定了起点和终点来确定液体流动方向,

例如设置此管路从A阀门到B阀门,那么当计算出的通路中为[A,B]则为正向流,[B,A]则为反向流,这样我们就可以从返回的结果中拿到每一根管路的连通及液体流动方向

解决上述需求中多起点多终点的每条管路的冲突问题

实际场景中,我们会有管路压力计,管路一定是从高压流向低压,所以可以通过压力来计算流向

  1. 处理阀门开关状态

  2. 根据开关使用下述算法计算出所有起点到终点通路(这里多起点和多终点就多次调用,调用次数为 startNode * endNode次)

  3. 根据每条通路的所有点位转换成管路实体,并且表明此通路中的每条管路流效方向正负

  4. 根据通路拿到有序压力计

  5. 判断压力计与压力计之间的差值,如果都大于等于0(有可能会出现前后管路压力一致的问题),则通路保留,否则删除此通路

  6. 拿到剩余所有的通路,将所有通路的每一条管路进行分组,

  7. 其中管路在所有通路中出现多次并且管路的流效方向不同为正或负,则取此管路在每条通路中的压力差(这里从管路前取压力差包括自身,管路后不包括)

  8. 拿到 g 中描述的所有的管路的压力差,从最大的一条通路开始删除错误流向的通路

  9. 删除时取压力最大的为正确方向,并删除非此方向的所有通路

  10. 然后重复 f g h流程操作,当所有管路都为正或负,则结束流程

  11. 此时会拿到所有的并且是每根管路不冲突的通路,根据自己需求处理即可

随便画一个图简单描述下

上图所示,假定起点为点1,终点为点3,图中边有边{1,5},{5,6},{5,7},{7,8}...等

代码结果返回所有从点1到点3的所有点的有序集合

例如返回[{1,5,15,3},{1,5,6,9,15,3}...]等

如果点6关闭,则上述结果中的第二个元素将被排除掉,即最后的结果为[{1,5,15,3}...]等

下面直接贴代码(代码中的测试数据非常长,并且不是从1开始的,代码只从所有边中找临近边,不关心点号)

代码注释的非常详细,并且在我main方法中提供了三组测试数据供参考测试

import java.util.ArrayList;

public class CalculateRoute {

    // 功能:给定点、边、起始点、终止点和各个点的开关状态,返回所有从起点到终点的通路,可以为空或多条
    //输入数据格式:
    //1. 点从1开始连续编号,提供管路列表;每个点的最大连接管路数为nMaxAdjPoints=4 (实际为3)
    //2. 设定起点和终点数组,{{起点1,终点1},{起点2,终点2},……},点号表示(从1开始)
    //3. 设定状态为关的点,点号表示;其余点都为开

    //返回: ArrayList<ArrayList>,所有路径的列表

    public static void main(String[] args) throws Exception {
        // 构造测试数据集
        int[][] Edges = new int[][]{{94, 5}, {103, 201}, {104, 28}, {105, 131}, {95, 11}, {95, 12}, {122, 7}, {96, 99}, {123, 242}, {124, 125}, {125, 236}, {125, 199}, {126, 127}, {127, 235}, {127, 200}, {128, 239}, {128, 51}, {129, 160}, {129, 240}, {130, 241}, {130, 136}, {131, 136}, {132, 101}, {132, 24}, {97, 100}, {133, 19}, {133, 103}, {134, 96}, {134, 52}, {135, 131}, {136, 203}, {137, 138}, {137, 21}, {138, 139}, {139, 22}, {139, 42}, {140, 274}, {140, 41}, {141, 47}, {141, 48}, {142, 143}, {142, 26}, {98, 13}, {98, 14}, {143, 147}, {143, 206}, {144, 8}, {144, 9}, {145, 255}, {145, 256}, {146, 208}, {146, 10}, {147, 27}, {147, 49}, {148, 136}, {149, 252}, {149, 260}, {150, 250}, {150, 214}, {151, 152}, {151, 215}, {152, 216}, {152, 218}, {99, 104}, {153, 32}, {154, 36}, {155, 251}, {156, 222}, {156, 262}, {157, 34}, {158, 253}, {158, 45}, {159, 259}, {161, 156}, {161, 224}, {162, 252}, {162, 44}, {100, 105}, {101, 18}, {102, 15}, {102, 16}, {236, 122}, {239, 129}, {240, 134}, {241, 204}, {242, 97}, {246, 263}, {247, 149}, {248, 150}, {250, 261}, {251, 275}, {252, 155}, {252, 261}, {253, 151}, {253, 225}, {235, 122}, {225, 226}, {173, 174}, {174, 103}, {164, 165}, {165, 94}, {193, 124}, {194, 124}, {195, 123}, {196, 126}, {197, 126}, {198, 123}, {202, 135}, {203, 210}, {205, 213}, {213, 39}, {206, 207}, {207, 23}, {209, 212}, {210, 246}, {212, 264}, {216, 217}, {217, 40}, {218, 219}, {219, 264}, {221, 46}, {222, 221}, {223, 158}, {224, 223}, {226, 265}, {169, 170}, {170, 101}, {262, 155}, {266, 1}, {267, 2}, {268, 3}, {260, 248}, {32, 259}, {33, 153}, {19, 140}, {20, 137}, {21, 257}, {22, 43}, {23, 138}, {1, 164}, {2, 169}, {3, 173}, {36, 220}, {34, 159}, {37, 154}, {35, 157}, {24, 141}, {25, 142}, {26, 258}, {27, 50}, {18, 133}, {5, 132}, {6, 94}, {8, 256}, {9, 255}, {10, 145}, {7, 128}, {28, 135}, {13, 54}, {15, 55}, {12, 58}, {14, 59}, {16, 60}, {39, 153}, {40, 33}, {274, 20}, {41, 257}, {42, 205}, {43, 148}, {275, 154}, {44, 157}, {46, 37}, {45, 35}, {47, 25}, {48, 258}, {49, 209}, {50, 148}, {51, 144}, {52, 146}, {53, 97}, {54, 100}, {55, 105}, {58, 96}, {59, 99}, {60, 104}, {272, 162}, {277, 161}, {261, 253}, {11, 53}, {279, 247}, {159, 278}};
        int[][] StartEndPoints = {{266, 259}};  //{起始点,终止点}数组
        ArrayList<Integer> OffPoints = new ArrayList<Integer>() {{
            add(6);
            add(105);
            add(11);
            add(201);
            add(213);
            add(143);
            add(40);
        }}; //设置为关的点

/*//        int[][] Edges=new int[][]{{ 577,407 },{ 580,416 },{ 583,424 },{ 512,415 },{ 513,512 },{ 514,513 },{ 515,516 },{ 515,518 },{ 516,517 },{ 516,519 },{ 517,520 },{ 517,432 },{ 518,412 },{ 518,413 },{ 519,421 },{ 519,422 },{ 520,429 },{ 520,430 },{ 521,522 },{ 521,456 },{ 522,466 },{ 522,469 },{ 523,524 },{ 524,525 },{ 525,464 },{ 525,467 },{ 526,527 },{ 527,528 },{ 528,529 },{ 529,449 },{ 529,453 },{ 530,531 },{ 531,532 },{ 532,533 },{ 532,438 },{ 533,534 },{ 533,440 },{ 534,443 },{ 534,445 },{ 535,538 },{ 536,433 },{ 538,540 },{ 538,470 },{ 539,555 },{ 540,541 },{ 541,607 },{ 541,452 },{ 542,539 },{ 543,544 },{ 544,545 },{ 545,557 },{ 545,457 },{ 546,547 },{ 547,548 },{ 547,558 },{ 548,460 },{ 548,461 },{ 549,600 },{ 550,441 },{ 550,442 },{ 551,552 },{ 552,553 },{ 553,560 },{ 553,450 },{ 554,539 },{ 555,453 },{ 555,454 },{ 556,599 },{ 557,404 },{ 557,458 },{ 558,606 },{ 558,459 },{ 559,540 },{ 560,406 },{ 560,451 },{ 561,592 },{ 561,594 },{ 562,468 },{ 563,564 },{ 563,598 },{ 564,565 },{ 564,471 },{ 565,574 },{ 565,472 },{ 566,475 },{ 566,477 },{ 567,474 },{ 567,476 },{ 568,489 },{ 570,479 },{ 570,480 },{ 571,482 },{ 571,483 },{ 572,601 },{ 572,490 },{ 573,602 },{ 573,491 },{ 584,437 },{ 585,434 },{ 639,608 },{ 640,610 },{ 641,612 },{ 642,614 },{ 400,439 },{ 401,550 },{ 402,444 },{ 403,544 },{ 404,462 },{ 405,552 },{ 406,455 },{ 593,488 },{ 595,487 },{ 596,465 },{ 618,531 },{ 626,530 },{ 627,530 },{ 606,559 },{ 607,542 },{ 608,512 },{ 610,513 },{ 612,514 },{ 614,514 },{ 599,566 },{ 600,567 },{ 587,497 },{ 589,493 },{ 591,492 },{ 424,618 },{ 407,627 },{ 412,576 },{ 413,575 },{ 415,515 },{ 416,626 },{ 421,579 },{ 422,578 },{ 429,582 },{ 430,581 },{ 432,536 },{ 433,521 },{ 434,535 },{ 437,536 },{ 438,586 },{ 439,543 },{ 440,588 },{ 441,543 },{ 442,551 },{ 443,590 },{ 444,551 },{ 445,535 },{ 449,405 },{ 450,554 },{ 451,554 },{ 452,542 },{ 454,556 },{ 455,556 },{ 456,403 },{ 457,546 },{ 458,546 },{ 459,559 },{ 460,528 },{ 461,549 },{ 462,549 },{ 464,597 },{ 465,526 },{ 466,523 },{ 467,526 },{ 468,523 },{ 469,561 },{ 470,563 },{ 471,524 },{ 472,527 },{ 474,568 },{ 475,568 },{ 476,644 },{ 477,643 },{ 479,572 },{ 480,571 },{ 482,573 },{ 485,562 },{ 486,562 },{ 487,485 },{ 489,603 },{ 490,604 },{ 491,605 },{ 488,486 },{ 643,570 },{ 644,483 },{ 492,402 },{ 493,401 },{ 497,400 },{ 586,587 },{ 588,589},{590,591}};
        int[][] Edges=new int[][]{{ 113,56 },{ 114,57 },{ 30,274 },{ 31,275 },{ 56,30 },{ 57,31 },{ 110,104 },{ 102,173 },{ 102,175 },{ 103,29 },{ 104,115 },{ 105,223 },{ 105,182 },{ 106,224 },{ 106,183 },{ 107,108 },{ 108,229 },{ 109,110 },{ 111,105 },{ 112,106 },{ 113,114 },{ 114,230 },{ 115,116 },{ 115,187 },{ 116,117 },{ 116,69 },{ 117,70 },{ 117,188 },{ 223,108 },{ 241,258 },{ 224,107 },{ 69,278 },{ 70,279 },{ 228,107 },{ 229,103 },{ 230,186 },{ 173,174 },{ 176,111 },{ 177,111 },{ 178,110 },{ 179,112 },{ 180,112 },{ 181,109 },{ 184,228 },{ 185,109 },{ 187,207 },{ 207,241 },{ 280,4 },{ 281,282 },{ 174,103 },{ 4,102 },{ 17,38 },{ 29,113 },{ 38,104 },{ 282,17 },{ 316,282 },{ 316,320 },{ 316,322 },{ 317,321 },{ 317,323 },{ 286,319 },{ 319,318 },{ 318,317 },{ 317,316 }};
        int [][] StartEndPoints={{280,275}};*/
//        ArrayList<Integer> OffPoints =new ArrayList<Integer> ();
        long begintime = System.currentTimeMillis();
        // 调用此函数即可
        ArrayList<ArrayList<Integer>> RoutesFound = findRoutes(Edges, StartEndPoints, OffPoints);
        long endtime = System.currentTimeMillis();

        System.out.println("找到的通路数: " + RoutesFound.size());
        for (int i = 0; i < RoutesFound.size(); i++) System.out.println(RoutesFound.get(i));
        System.out.println("总用时" + (endtime - begintime) + "毫秒");
    }

    public static ArrayList<ArrayList<Integer>> findRoutes(int[][] Edges, int[][] StartEndPoints, ArrayList<Integer> OffPoints) {
        ArrayList<ArrayList<Integer>> routes = new ArrayList<ArrayList<Integer>>();

        int i, j;
        int nPoints = 0;  //最大点号,从1开始计数

        //int nMaxAdjPoints=4;  //本程序中,默认每个点的最大连接边数是3

        // 首先剔除状态为关的边,并将需要计算的边存为新的数组
        // 得到有效的边数 nEdges,存储边的数组 EdgesReady
        int nEdges = 0;
        int[][] EdgesReady = new int[Edges.length][2];
        for (i = 0; i < Edges.length; i++) {
            if (!OffPoints.contains(Edges[i][0]) && !OffPoints.contains(Edges[i][1])) {
                EdgesReady[nEdges][0] = Edges[i][0];
                EdgesReady[nEdges][1] = Edges[i][1];
                nEdges++;
            }
        }


        // 计算最大点号数 nPoints
        for (i = 0; i < nEdges; i++) {
            if (EdgesReady[i][0] > nPoints) nPoints = EdgesReady[i][0];
            if (EdgesReady[i][1] > nPoints) nPoints = EdgesReady[i][1];
        }

        // 计算每个点的邻近点数组
        ArrayList<ArrayList<Integer>> adjPoints = new ArrayList<ArrayList<Integer>>();
        for (i = 1; i < nPoints + 1; i++) {
            ArrayList<Integer> list = new ArrayList<Integer>();
            for (j = 0; j < nEdges; j++) {
                if (EdgesReady[j][0] == i || EdgesReady[j][1] == i) {
                    list.add(EdgesReady[j][0] + EdgesReady[j][1] - i);
                }
            }
            adjPoints.add(list);
        }
        if (!adjPoints.isEmpty()) {
            // 此时,数据预处理完成,得到最大点号数 nPoints,邻近点数组 adjPoints
            // 对点 N(从1开始),其临近点数组为 adjPoints[N-1],长度为4,存储相邻点的数组序号(从1开始)
            // 如点1有边[1,10],[1,22],则 adjPoints[0]={10,22,-1,-1}

            // 开始递归计算通路,对每一组<起点,终点>组合
            // path存储当前路径,如该路径是可行通路,则添加到routes列表中

            ArrayList<Integer> path = new ArrayList<Integer>();
            for (i = 0; i < StartEndPoints.length; i++) {
                path.clear();
                findPath(adjPoints, StartEndPoints[i][0], StartEndPoints[i][1], path, routes);
            }
        }
        return routes;
    }

    // 递归查找通路:
    // adjP:临近点数组
    // p:当前查找点
    // endP:终点
    // path:存储当前找到的路径
    private static void findPath(ArrayList<ArrayList<Integer>> adjP, int p, int endP, ArrayList<Integer> path, ArrayList<ArrayList<Integer>> routes) {
        int i;

        // 如果当前点已经在路径中,返回;否则将当前点添加到当前路径  
        if (path.contains(p)) return;

        // 需设定当前时刻的路径
        ArrayList<Integer> currentPath = new ArrayList<>(path);
        currentPath.add(p);

        // System.out.println("当前路径: "+currentPath);

        // 如果当前点为终点,则成功找到1条路径,更新路径结果列表,并返回
        if (p == endP) {
            routes.add(currentPath);
            return;
        }

        // 否则,递归查找此点的所有邻近点
        for (i = 0; i < adjP.get(p - 1).size(); i++) {
            findPath(adjP, adjP.get(p - 1).get(i), endP, currentPath, routes);
        }
    }
}

测试结果

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
我们可以使用深度优先搜索(DFS)算法来求无向连通连通分量数。具体实现步骤如下: 1. 初始化一个变量count,用于记录连通分量数,初始值为0。 2. 创建一个布尔数组visited,用于记录每个节点是否被访问过,初始值为false。 3. 对于中的每个未被访问过的节点,执行以下步骤: 1. 将当前节点标记为已访问。 2. 递归访问当前节点的所有未被访问的邻居节点。 3. 递归访问结束后,将count加1,表示发现了一个新的连通分量。 4. 返回count,即为无向连通连通分量数。 以下是使用C++实现的示例代码: ```cpp #include <iostream> #include <vector> using namespace std; void dfs(int u, vector<bool>& visited, vector<vector<int>>& adj) { visited[u] = true; for (int v : adj[u]) { if (!visited[v]) { dfs(v, visited, adj); } } } int countConnectedComponents(vector<vector<int>>& adj) { int n = adj.size(); vector<bool> visited(n, false); int count = 0; for (int i = 0; i < n; i++) { if (!visited[i]) { dfs(i, visited, adj); count++; } } return count; } int main() { int n, m; cin >> n >> m; // 输入节点数和边数 vector<vector<int>> adj(n); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; // 输入一条边的两个端点 adj[u].push_back(v); adj[v].push_back(u); // 无向需要双向加边 } int count = countConnectedComponents(adj); // 求连通分量数 cout << count << endl; return 0; } ``` 其中,adj是邻接表表示的无向,adj[u]表示与节点u相邻的所有节点。输入格式为第一行两个整数n和m,分别表示节点数和边数;接下来m行每行两个整数u和v,表示一条边的两个端点。输出无向连通连通分量数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值