• 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)

  • 相关阅读:
    JavaScript 核心参考 Arguments 对象
    readonly 和 disable的区别
    Asp.net 页面导航的几种方法与比较(转)
    CSS float clear 使用
    PHP时区列表
    Jquery 父窗口中移进移出鼠标到Iframe: 移进显示更多内容, 移出隐藏部分内容
    Mysql 查看进程SQL
    好用的弹出对话框 artDialog
    In Cache 算法
    live 绑定事件会触发多次
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10780452.html
Copyright © 2020-2023  润新知