zoukankan      html  css  js  c++  java
  • TYVJ1391 走廊泼水节

    题意

    给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树。
    求增加的边的权值总和最小是多少。

    输入格式

    第一行包含整数t,表示共有t组测试数据。
    对于每组测试数据,第一行包含整数N。
    接下来N-1行,每行三个整数X,Y,Z,表示X节点与Y节点之间存在一条边,长度为Z。

    输出格式

    每组数据输出一个整数,表示权值总和最小值。
    每个结果占一行。

    数据范围

    (N≤6000,Z≤100)

    根据Kruskal的过程,如果有边e1,e2,e3。e3权值大于e2,e2大于e1。如果加入e1后,加e2会构成环,就不加e2。
    所以我们对于每条边(u,v)如果u,v不连通,就加上若干条权值为z+1的边。显然这些边不可能是最小生成树的一部分。每次加的边数应该是size[u] * size[v] - 1。
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    int fa[7000],siz[7000];
    int find(int x){ 
    	if(fa[x] == x){
    		return fa[x];
    	}
    	else{
    		return fa[x] = find(fa[x]);
    	}
    }
    void merge(int fx,int fy){
    	fa[fx] = fy;
    	siz[fy] += siz[fx];
    }
    struct Edge{
    	int u,v,w;
    	bool operator < (const Edge& a){
    		return w < a.w;
    	}
    }e[7000];
    int cnt; 
    long long kruskal(){
    	long long ans = 0;
    	sort(e + 1,e + cnt + 1);
    	for(int i = 1; i <= cnt; ++i){
    		int fx = find(e[i].u),fy = find(e[i].v);
    		if(fx != fy) {
    			ans += (siz[fx] * siz[fy] - 1) * (e[i].w + 1);
    			merge(fx,fy);
    		}
    	}
    	return ans;
    }
    int main(){
    	int t;
    	cin >> t;
    	while(t--){
    		cnt = 0;
    		int n;
    		cin >> n;
    		for(int i = 1; i <= n; ++i){
    			fa[i] = i; siz[i] = 1;
    		}	
    		for(int i = 1; i <= n - 1; ++i){
    			int x,y,z;
    			cin >> x >> y >> z;
    			e[++cnt].u = x;
    			e[cnt].v = y;
    			e[cnt].w = z;
    		}
    		cout << kruskal() << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    python .npy 存取 dict
    python 找零钱方案
    docker 容器里显示图形
    docker 安装vim
    软件测试基础知识
    Git命令——学习笔记2
    Git命令——学习笔记1
    Win10配置Git环境变量与基本使用
    Selenium Web自动化测试——基于unittest框架的PO设计模式
    Django+Celery学习笔记5——定时推送消息
  • 原文地址:https://www.cnblogs.com/FoxC/p/11419289.html
Copyright © 2011-2022 走看看