次小生成树探讨

借鉴自:https://www.cnblogs.com/hxsyl/p/3290832.html

最小生成树prime算法讲解:https://www.cnblogs.com/aiyelinglong/archive/2012/03/26/2418707.html

先用prim求出最小生成树T,在prim的同时,

用一个矩阵maxd[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值.(有些拗口),

这是很容易做到的,因为prim是每次增加一个结点s, 在此需要保存节点和其父节点,

采用DP,则最大权值要么是新加入的边,要么是父节点到起始点的采用DP算出来的距离

//temp是将要加入集合的点(还没有加入),pre[temp]是temp的父结点

for
(int j=1; j<=n; j++) if(vis[j]) maxd[temp][j] = maxd[j][temp] = max(mincost, maxd[pre[temp]][j]);

以下是POJ-1679的代码  就是一个次小生成树 模板题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 10010, INF = 0x7fffffff;
typedef long long LL;
int graph[510][510], d[maxn], vis[maxn], maxd[510][510], pre[maxn];
int n, m;

int prime(int s)
{
    int temp, sum = 0;
    mem(vis, 0);
    for(int i=1; i<=n; i++) d[i] = graph[s][i], pre[i] = s;
    vis[s] = 1;
    d[s] = 0;
    for(int i=1; i<n; i++)
    {
        int mincost = INF;
        for(int j=1; j<=n; j++)
        {
            if(!vis[j] && mincost > d[j])
                mincost = d[j], temp = j;
        }
        for(int j=1; j<=n; j++)
            if(vis[j]) maxd[temp][j] = maxd[j][temp] = max(mincost, maxd[pre[temp]][j]);
        vis[temp] = 1;
        sum += mincost;
        for(int j=1; j<=n; j++)
        {
            if(!vis[j] && d[j] > graph[temp][j])
                d[j] = graph[temp][j], pre[j] = temp;
        }
    }
//    for(int i=1; i<=n; i++)
//        sum += d[i];
    return sum;
}


int main()
{
    int T;
    cin>> T;
    while(T--)
    {
        cin>> n >> m;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(i == j) graph[i][j] = 0;
                else graph[i][j] = graph[j][i] = INF;
        for(int i=0; i<m; i++)
        {
            int u, v, w;
            cin>> u >> v >> w;
            graph[u][v] = graph[v][u] = w;
        }
        int sum = prime(1);
        int lsum = INF;
        for(int i=1; i<=n; i++)
            for(int j=i+1; j<=n; j++)
            {
            if(i != pre[j] && j != pre[i]  && graph[i][j] != INF)  //找到不在最小生成树里的边 (在最小生成树里的边 对于i和j一定其中一个是另一个的父结点)
                if(sum - maxd[i][j] + graph[i][j] < lsum)   //更新生成树  直至找到次小生成树
                    lsum = sum - maxd[i][j] + graph[i][j];
            }

        if(lsum == sum)
            cout<< "Not Unique!" <<endl;
        else
            cout<< sum <<endl;

    }



    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WTSRUVF/p/9415525.html
今日推荐