• Luogu P4716 【模板】最小树形图


    题目链接(Click) (Here)

    不知道有什么用的一个东西。本来不打算再大量扩知识点了但还是学一下好了,反正也不难。

    原理:树上父亲唯一,每次选最短的父边。

    此时会有两类情况:

    • 就这样正常连下去,这样我们就得到了一个尽可能小的树形图。

    • 成环。这种情况下我们需要拆掉环里的一条边换成其他的边。

    我们记录一下到达每个点的最短父边权值是多少。对于成环的情况,可以先把环里面所有边的权值选上,把环里面的所有点看成一个。然后等到有其它外来的边连进来的时候,再选一个最小的外来边,去掉环里面原先所暂时使用的边,换成外来的那个,就这样一直求解直到不再有环。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    const int N = 100 + 5;
    const int M = 10000 + 5;
    const ll INF = 0x3f3f3f3f;
    
    int n, m, r;
    
    struct edge {int u, v, w;} e[M];
    
    int fa[N], id[N], top[N], minw[N];
    
    ll get_ans (int n, int m) {
    	ll ans = 0;
        while (true) {
        	int cnt = 0;
    		for (int i = 1; i <= n; ++i) {
    			id[i] = top[i] = 0; minw[i] = INF;
    		}
            for (int i = 0; i < m; ++i) {
            	if (e[i].u != e[i].v && e[i].w < minw[e[i].v]) {
                	fa[e[i].v] = e[i].u;
    				minw[e[i].v] = e[i].w;
                }
            }
            minw[r] = 0;
            for (int i = 1; i <= n; ++i) {
                if (minw[i] == INF) return -1;
                ans += minw[i];
                int u = i;
    			while (u != r && top[u] != i && !id[u]) {
    				top[u] = i;
             		u = fa[u];
    		    }
                if (u != r && !id[u]) {
                    id[u] = ++cnt;
                    for (int v = fa[u]; v != u; v = fa[v]) id[v] = cnt;
                }
            }
    		if (cnt == 0) return ans;
            for (int i = 1; i <= n; ++i) {
    			if (!id[i]) id[i] = ++cnt;
    		}
    		for (int i = 0; i < m; ++i) {
                int prew = minw[e[i].v];
                e[i].u = id[e[i].u];
                e[i].v = id[e[i].v];
                if (e[i].u != e[i].v) {
    				e[i].w -= prew;
    			}
            }
    		n = cnt; r = id[r];
        }
    }
    
    int main () {
    	cin >> n >> m >> r;
        for (int i = 0; i < m; ++i) {
        	static int u, v, w;
        	cin >> u >> v >> w; 
    		e[i] = (edge) {u, v, w};
    	}
    	cout << get_ans (n, m) << endl;
    }
    

    以及非常感谢 @旋转卡壳 的代码。仅仅是读注释就可以快速理解整个算法的流程。(虽然代码不加空格(www)

  • 相关阅读:
    Java NIO开发需要注意的陷阱(转)
    Java Nio注意事项
    NIO的介绍及使用(总结)
    蓝萝卜blu netty3升netty4
    tcp nio 远程主机强迫关闭了一个现有的连接
    java 竖线分割字符串的问题
    15个免费好用的抓包工具
    JSP 基础之 JSTL <c:forEach>用法
    JSP中多条件判断
    怎么不让控制台system.out.println()打印
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10780452.html
Copyright © 2020-2023  润新知