• 全连通图求最小生成树边权之积(邻接矩阵/prim/kruskal)


    Description

    大家都知道最小生成树一般求的是构成最小生成树的边的权值之和。
    现在请求构成最小生成树的边的权值之积 S,最终结果请输出 (S % 100003)。
    P.S. 点之间的边为无向边,矩阵保证符合无向图的对称性。

    Input

    多组数据。

    第一行,整数N,表示N个点。(0 < N <= 100)

    接下来为一个N*N 保证合法的邻接矩阵,矩阵内均为自然数。

    Output

    每组数据输出一行整数结果。

    Sample Input

    3
    0 1 2
    1 0 3
    2 3 0
    2
    0 5
    5 0

    Prim

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 #define MAX 105
     6 #define INF 0x7FFFFFFF
     7 int map[MAX][MAX];  // adjacency matrix
     8 bool vis[MAX];  // is the node i visited
     9 int dis[MAX];  // distance between current node and other node i
    10 
    11 void prim(int n) {
    12     memset(vis, false, sizeof(vis));
    13 
    14     // current node is 0
    15     int cur = 0;
    16     for (int i = 0; i < n; ++i)
    17         dis[i] = map[cur][i];  // dis[] store distance between other nodes and 0
    18     vis[cur] = true;
    19 
    20     unsigned long long s = 1;
    21     for (int i = 0; i < n - 1; ++i) {
    22         // find the shortest edge between cur and other unvisited nodes
    23         int min = INF;
    24         for(int j = 0; j < n; ++j)
    25             if (!vis[j] && dis[j] < min)
    26                 min = dis[cur = j];  // update to next shortest edge and potential cur
    27 
    28         // the other end is visited and is now current node
    29         s *= min;
    30         s %= 100003;
    31         vis[cur] = true;
    32 
    33         // update dis[] to store distance between other nodes and cur
    34         // if the node is visited, leave it
    35         for (int j = 0; j < n; ++j)
    36             if (!vis[j] && map[cur][j] < dis[j])
    37                 dis[j] = map[cur][j];
    38     }
    39     cout << (s % 100003) << endl;
    40 }
    41 
    42 int main() {
    43     int n;
    44 
    45     while(scanf("%d", &n) != EOF) {
    46         for (int i = 0; i < n; ++i)
    47             for (int j = 0; j < n; ++j)
    48                 scanf("%d", &map[i][j]);
    49         prim(n);
    50     }
    51 
    52     return 0;
    53 }

    Kruskal,其实改装成了边表,加了并查集,有做路径压缩,可以水过就懒得写带rank的优化了……

     1 #include <iostream>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define MAX 105
     7 #define INF 0x7FFFFFFF
     8 
     9 int root[MAX];
    10 int map[MAX][MAX];
    11 
    12 struct Edge {
    13     int u, v;
    14     int d;
    15 } e[MAX*MAX];
    16 
    17 bool cmp(Edge a, Edge b) {
    18     return a.d < b.d;
    19 }
    20 
    21 int find(int x) {
    22     while(x != root[x]) {
    23          root[x] = root[root[x]];  // compress
    24         x = root[x];
    25     }
    26     return x;
    27 }
    28 
    29 unsigned long long kruskal(int vn, int en) {
    30     unsigned long long p = 1;
    31 
    32     // connect to itself
    33     for (int i = 0; i < vn; ++i)
    34         root[i] = i;
    35 
    36     // sort edges by length
    37     std::sort(e, e+en, cmp);
    38 
    39     for(int i = 0; i < en; ++i) {
    40         int ru = find(e[i].u);
    41         int rv = find(e[i].v);
    42         if(ru != rv) {  // the ends of e[i] are not in the same spanning tree
    43             root[ru] = rv;  // merge
    44             p *= e[i].d;
    45             p %= 100003;
    46         }
    47     }
    48 
    49     return p;
    50 }
    51 
    52 int main() {
    53     int vn;
    54     while(cin >> vn) {
    55         memset(map, 0, sizeof(map));
    56         for(int i = 0; i < vn; ++i)
    57             for(int j = 0; j < vn; ++j)
    58                 cin >> map[i][j];
    59 
    60         int en = 0;
    61         for(int i = 0; i < vn; ++i)  // use upper-right corner
    62             for(int j = i + 1; j < vn; ++j) {
    63                 // transform to adjacency list
    64                 e[en].u = i;
    65                 e[en].v = j;
    66                 e[en].d = map[i][j];
    67                 ++en;
    68             }
    69            cout << kruskal(vn, en) % 100003 << '
    ';
    70     }
    71     return 0;
    72 }

    因为数据太大所以每次乘完都要取模,不然会溢出。

    因为本来就给的是邻接矩阵,kruskal要多做一步处理转换成边表,速度大约是prim的一半

  • 相关阅读:
    Git 操作
    SVN
    一维数组
    常见的数学方法
    常用事件
    function函数
    while;do while; for循环
    JS中的变量提升
    关于js的单双引号嵌套问题
    db.collection is not a function
  • 原文地址:https://www.cnblogs.com/joyeecheung/p/3505292.html
Copyright © 2020-2023  润新知