• 九度OJ 1249:次小生成树 (次小生成树)


    时间限制:1 秒

    内存限制:32 兆

    特殊判题:

    提交:203

    解决:56

    题目描述:

    最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树。

    输入:

    存在多组数据,第一行一个正整数t,表示有t组数据。
    每组数据第一行有两个整数n和m(2<=n<=100),之后m行,每行三个正整数s,e,w,表示s到e的双向路的权值为w。

    输出:

    输出次小生成树的值,如果不存在输出-1。

    样例输入:
    2
    3 3
    1 2 1
    2 3 2
    3 1 3
    4 4
    1 2 2
    2 3 2
    3 4 2
    4 1 2
    样例输出:
    4
    6

    思路:

    求给定图的次小生成树。
    对于给定的图,我们可以证明,次小生成树可以由最小生成树变换一边得到。那么我们可以如下求给定图的次小生成树。首先,我们用prime算法求出图的最小生成树,在这个过程中记录每条边是否用过,以及两个点之间最短路径上的最大权值F[i,j]
    F[i,j]可以如此求得,当加入点u的时候,并且u的父结点是v 那么对于已经在生成树中的节点x
    F[x,u] = max(F[x,v], weight[u][v]),那么我么就可以用Prime算法一样的时间复杂度来求出图的次小生成树。


    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define INF 0x3f3f3f3f
     
    int T, n, m;
    int G[110][110], F[110], M[110][110], mark[110];
     
     
    int max(int x, int y) {
        return x > y ? x : y;
    }
     
     
    void dfs(int src, int pre, int now) {
        if (mark[now]) return;
        //printf("dfs %d %d
    ", src, now);
     
        if (src == now) {
            M[src][now] = M[now][src] = 0;
        }else {
            M[src][now] = max(G[pre][now], M[src][pre]);
            M[now][src] = M[src][now];
            //printf("update M(%d,%d) = %d
    ", now, src, M[src][now]);
        }
     
        mark[now] = 1;
     
        int i;
        for (i=1; i<=n; i++)
            if (F[i] == now || F[now] == i) {
                dfs(src, now, i);
            }
    }
     
    int main()
    {
        scanf("%d", &T);
     
        while (T--) {
            scanf("%d%d", &n, &m);
     
            memset(G, INF, sizeof G);
            int i, j;
            for (i=0; i<m; i++) {
                int a, b, c;
                scanf("%d%d%d", &a, &b, &c);
                G[a][b] = G[b][a] = c;
            }
     
            // prim
            int dist[110], min_sum=0;
            memset(dist, INF, sizeof dist);
            memset(F, -1, sizeof F);
            memset(mark, 0, sizeof mark);
            dist[1] = 0;
            while (1) {
                j = 0;
                for (i=1; i<=n; i++)
                    if (!mark[i] && dist[i] < dist[j]) j = i;
     
                if (j == 0) break;
                min_sum += dist[j];
                mark[j] = 1;
     
                for (i=1; i<=n; i++)
                    if (!mark[i] && dist[i] > G[j][i]) {
                        dist[i] = G[j][i];
                        F[i] = j;
                    }
            }
     
            // now we get the max_path of i to j
            memset(M, 0, sizeof M);
            for (i=1; i<=n; i++) {
                memset(mark, 0, sizeof mark);
                dfs(i, i, i);
            }
     
            int ans = INF;
            // try delete i-j
            for (i=1; i<=n; i++)
                for (j=1; j<=n; j++) {
                    if (i!=j && F[j] != i && F[i] != j && min_sum + G[i][j] - M[i][j] < ans) {
                        ans = min_sum + G[i][j] - M[i][j];
                        //printf("ans : min_sum + G[%d][%d] - M[%d][%d] = %d
    ", i, j, i, j, ans);
                    }
                }
     
            printf("%d
    ", ans);
        }
     
        return 0;
    }
     
    /**************************************************************
        Problem: 1249
        User: warcraftw
        Language: C
        Result: Accepted
        Time:20 ms
        Memory:1008 kb
    ****************************************************************/


    编程算法爱好者。
  • 相关阅读:
    扩展kmp
    计算几何板子
    组合数板子
    SecureML: A System for Scalable Privacy-Preserving Machine Learning 论文笔记
    mac任务管理器快捷键
    后缀数组
    poj 1144 Network【图的割点】模板
    CSU 1162【Balls in the Boxes】
    CSU 1111【三家人】数学题
    P1330 封锁阳光大学【二分染色】
  • 原文地址:https://www.cnblogs.com/liangrx06/p/5083815.html
Copyright © 2020-2023  润新知