Day12 次小生成树(这题是求有没有两个最小生成树)

题目链接:点击打开链接

思想:首先用prim算法求一遍最小生成树,在求的过程中维护一个数组max_len来存最小生成树中的点i到j这条路径上最大的一条边,为了维护这个数组还要记录每个最小生成树节点的前驱节点pre。然后遍历每一条不在树上的边e(i,j),比较e(i,j)和max_len[i][j]的大小,如果一样大说明可以有第二个最小生成树了,如果一直都找不到和它一样大的说明不存在。求次小生成树就是找到最小的max_len[i][j]-e[i][j]加到原来生成树的答案上面。

代码:(参考:点击打开链接

#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
const int inf = 1000000005;
int grid[105][105],max_len[105][105],pre[105];
int vis[105],mincost[105];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        int x,y,l;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                grid[i][j] = grid[j][i] = inf;
            }
        }
        for(int i=1; i<=m; i++){
            scanf("%d%d%d",&x,&y,&l);
            grid[x][y] = grid[y][x] = l;
        }
        for(int i=1; i<=n; i++) mincost[i] = inf;
        mincost[1] = 0;
        memset(vis,false,sizeof(vis));
        memset(max_len,0,sizeof(max_len));
        int ans = 0;

        memset(pre,-1,sizeof(pre));

        //求最初的最小生成树
        while(true){
            int p = -1;
            for(int i=1; i<=n; i++){
                if(vis[i]==false && (p == -1 || mincost[i]<mincost[p]) ) p = i;
            }

            if(p == -1) break;

            vis[p] = true;
            ans += mincost[p];

            for(int i=1; i<=n; i++){
                if(vis[i] && (i!=p)){
                    max_len[i][p] = max_len[p][i] = max(max_len[pre[p]][i], mincost[p]);
                }
            }

            for(int i=1; i<=n; i++){
                if(vis[i] == false && mincost[i]>grid[p][i]){
                    mincost[i] = grid[i][p];
                    pre[i] = p;
                }
            }
        }
        int tmp = inf;

        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                //如果这条边不在最小生成树内
                if(i!=j && pre[i]!=j && pre[j]!=i){
                    tmp = min(tmp, grid[i][j] - max_len[i][j]);
                }
            }
        }

        //cout<<ans<<endl;

        if(tmp == 0) printf("Not Unique!\n");
        else printf("%d\n",ans);

    }
    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值