• 最小生成树 HihoCoder-1097、1098、1109(最小生成树算法)


    太久没写最小生成树了,快忘光了。这几天回顾了一下

    • 最小生成树一·Prim算法
      AC G++ 369ms 17MB
      #include "cstdio"
      using namespace std;
      const int INF = 0x3f3f3f3f;
      int road[1005][1005];
      int dis[1005], n, ans;
      bool vis[1005];
      void prim() {
          int v, mn;
          for (int i = 1; i <= n; i++) {
              dis[i] = road[1][i];
          }
          vis[1] = true;
          for (int i = 1; i < n; i++) {
              mn = INF;
              for (int j = 1; j <= n; j++) {
                  if (!vis[j] && dis[j] < mn) {
                      mn = dis[j];
                      v = j;
                  }
              }
              ans += dis[v];
              vis[v] = true;
              for (int j = 1; j <= n; j++) {
                  if (!vis[j] && dis[j] > road[v][j]) {
                      dis[j] = road[v][j];
                  }
                  /*
                  这个if改成如下写法就变成Dijkstra算法求最短路了
                  if (!vis[j] && dis[j] > dis[v] + road[v][j]) {
                      dis[j] = dis[v] + road[v][j];
                  }
                  */
              }
          }
      }
      int main() {
          scanf("%d", &n);
          for (int i = 1; i <= n; i++) {
              for (int j = 1; j <= n; j++) {
                  scanf("%d", &road[i][j]);
              }
          }
          prim();
          printf("%d
      ", ans);
          return 0;
      }

      理解了Dijkstra看这个就很容易了,改一下if语句多加一个ans就是了;

    • 最小生成树二·Kruscal算法
      AC G++ 342ms 17MB
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      const int INF = 0x3f3f3f3f;
      // 并查集
      int pre[100005];
      struct Road{
          int s, e, v;
      }road[1000005];
      bool cmp(Road n, Road m) {
          return n.v < m.v;
      }
      int find(int id) {
          if (pre[id] == 0) {
              return id;
          }
          return pre[id] = find(pre[id]);
      }
      int main() {
          int n, m, ans = 0;
          scanf("%d%d", &n, &m);
          for (int i = 0; i < m; i++) {
              scanf("%d%d%d", &road[i].s, &road[i].e, &road[i].v);
          }
          sort (road, road + m, cmp);
          // 用n - 1条边可以联通n个点,所以当n == 1的时候退出循环
          for (int i = 0; n != 1; i++) {
              int s = find(road[i].s);
              int e = find(road[i].e);
              if (s != e) {
                  pre[s] = e;
                  n--;
                  ans += road[i].v;
              }
          }
          printf("%d
      ", ans);
          return 0;
      }

      Kruscal算法有点贪心的意思在里面吧,每次取最短的边,当n个点被联通时退出循环

    • 最小生成树三·堆优化的Prim算法
      AC G++ 436ms 24MB
      #include "bits/stdc++.h"
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int INF = 0x3f3f3f3f;
      const int MAXN = 1e5 + 5;
      /* 
      road[i].first 存放以i为顶点的边的另一个顶点
      road[i].second 存放以i为顶点的边的长度
      */
      vector<PII> road[MAXN];
      int dis[MAXN];
      int ans;
      bool vis[MAXN];
      void prim() {
          // q表示就目前状态可以花费q.top.first的代价去联通q.top.second这个点
          priority_queue<PII, vector<PII>, greater<PII> > q;
          memset(dis, INF, sizeof(dis));
          q.push({0, 1});
          while (!q.empty()) {
              int id = q.top().second;
              if (vis[id]) {
                  // 如果id已经被联通,直接continue
                  q.pop();
                  continue;
              } else {
                  // 否则由于优先列队的排序,q.top.first一定是最小代价
                  ans += q.top().first;
                  q.pop();
              }
              vis[id] = true;
              for (auto i : road[id]) {
                  if (i.second < dis[i.first]) {
                      dis[i.first] = i.second;
                      q.push({i.second, i.first});
                  }
              }
          }
      }
      int main() {
          int n, m;
          int u, v, w;
          scanf("%d%d", &n, &m);
          while (m--) {
              scanf("%d%d%d", &u, &v, &w);
              road[u].push_back({v, w});
              road[v].push_back({u, w});
          }
          prim();
          printf("%d
      ", ans);
          return 0;
      }

      果然还是和dijkstra很像啊,仿照dijkstra的堆优化就好了。这种建图的方法倒是比原先用的链式前向星好写多了。

  • 相关阅读:
    如何在WinPE下安装xp安装版
    好用、功能强大的JQuery弹出层插件
    设计模式-旧话重提之类工厂的使用
    How can I manage Internet Explorer Security Zones via the registry?
    设计模式行为模式Behavioral Patterns()之FlexibleService模式
    how to design a new tree view control
    在C#中通过webdav操作exchange
    Yahoo! User Interface Library (哈偶然发现了这个东西)
    设计模式[2]旧话重提之工厂模式
    const和static readonly 的区别
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/10271234.html
Copyright © 2020-2023  润新知