Prim次小生成树

题目链接:1679:The Unique MST
分析:

  • 参考了这篇文章,该文章采用邻接矩阵,介绍了Kruskal和Prim两种方法,我们采用邻接表+Prim
  • 核心思想:
    • 在最小生成树上添加一条边,必然成环
    • 从环中删除一条边(不是新加进来的),新的总权值 ≥ \ge 旧的总权值
    • 如果相等则说明最小生成树不唯一
    • 从所有新权值中,选择不等于旧权值的最小的,就对应次小生成树
  • 具体实现:
    • 对于最小生成树,用数组connected[i][j]记录节点i与节点j之间是否连边,用数组maxedge[i][j]记录从i到j的路径上最大的边权重。两个数组随着prim算法的进行而更新。
    • 求出最小生成树后,如果两节点i,j间未连边,且从i到j的路径上最大边权重等于从i到j的边权重,则删一边加一边,又是最小生成树,于是不唯一。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int n, m;
int tot_weight = 0;
bool connected[MAXN][MAXN];
int maxedge[MAXN][MAXN];
bool vis[MAXN];

struct edge {
    
    
    int to;
    int weight;
    edge (int _to, int _weight) : to(_to), weight(_weight) {
    
    }
};
struct edge_p : public edge {
    
    
    int from; /* Special for Second MST */
    edge_p (const edge& e, int _pre) : edge(e), from(_pre) {
    
    }
    bool operator< (const edge_p& e) const {
    
    
        return weight > e.weight;
    }
};

vector<edge> nxt[MAXN];

void init()
{
    
    
    tot_weight = 0;
    memset(connected, 0, sizeof(connected));
    memset(maxedge, 0, sizeof(maxedge));
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i <= n; ++i)
        nxt[i].clear();
}

void prim()
{
    
    
    priority_queue<edge_p> pq;

    /* get ready */
    vis[1] = 1;
    for (edge e : nxt[1])
        pq.push(edge_p(e, 1));

    /* do it */
    for (int i = 1; i < n; ++i) {
    
    
        while (vis[pq.top().to])
            pq.pop();
        edge_p e = pq.top(); pq.pop();

        vis[e.to] = 1;
        tot_weight += e.weight;

        /* Special for Second MST */
        connected[e.to][e.from] = connected[e.from][e.to] = 1;
        for (int j = 1; j <= n; ++j)
            maxedge[e.to][j] = maxedge[j][e.to] = max(e.weight, maxedge[e.from][j]);
        
        for (edge t : nxt[e.to])
            if (!vis[t.to])
                pq.push(edge_p(t, e.to));
    }
}

int main()
{
    
    
    int T; cin >> T;
    while (T--) {
    
    
        cin >> n >> m;
        init();
        for (int i = 0; i < m; ++i) {
    
    
            int u, v, l;
            scanf("%d%d%d", &u, &v, &l);
            nxt[u].push_back(edge(v, l));
            nxt[v].push_back(edge(u, l));
        }
        prim();
        bool isunique = 1;
        for (int i = 1; i <= n; ++i) {
    
    
            for (edge e: nxt[i]) {
    
    
                if (!connected[i][e.to] && maxedge[i][e.to] == e.weight) {
    
    
                    isunique = 0;
                    goto END;
                }
            }
        }
        END:;
        if (isunique)
            printf("%d\n", tot_weight);
        else 
            printf("Not Unique!\n");
    }
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/w112348/article/details/111114882
今日推荐