最小生成树 & 洛谷P3366【模板】最小生成树 & 洛谷P2820 局域网
嗯...
理解生成树的概念:
在一幅图中将所有n个点连接起来的n-1条边所形成的树。
最小生成树:
边权之和最小的生成树。
最小瓶颈生成树:
对于带权图,最大权值最小的生成树。
如何操作?
1.Prim算法(O(mlogn))
2.Kruskal算法(O(mlogn))
推荐使用第二种,无需建图。
算法流程:
Prim算法:(思想类似dijkstra)
随意选取一个点作为已访问集合的第一个点,并将所有相连的边加入堆中
从堆中找到最小的连接集合内和集合外点的边,将边加入最小生成树中
将集合外点标记为已访问,并将相连边加入堆
重复以上过程直到所有点都在访问集合中
Kruskal算法:(并查集思想)
将边按照权值排序
依次枚举每一条边,若连接的两点不连通则加入最小生成树中
使用并查集维护连通性
模板代码:
- int f[], h;
- struct node{
- int x, y, l;
- } a[];
- inline bool cmp(node i, node j){
- return i.l < j.l;
- }
- inline int find(int x){
- if(x != f[x])//本身是否为父亲节点
- f[x] = find(f[x]);
- return f[x];
- }//并查集操作
- int main(){
- for(int i = ; i <= n; i++){
- f[i] = i;
- }//父节点初始化
- sort(a+, a+k+, cmp);//排序
- for(int i = ; i <= k; i++){
- int r1 = find(a[i].x);
- int r2 = find(a[i].y);
- if(r1 != r2){
- f[r1] = r2;
- }
- }
- }
Kruskal
- #include<bits/stdc++.h>
- using namespace std;
- int n,m,a,b,c;
- int sum;
- int g[][],minn[];
- bool u[];
- int main(){
- memset(g,0x7f,sizeof(g));
- memset(minn,0x7f,sizeof(minn));
- memset(u,true,sizeof(u));
- cin>>n>>m;
- for(int i=;i<=m;i++)
- {
- cin>>a>>b>>c;
- g[a][b]=g[b][a]=c;
- sum+=c;
- }
- minn[]=;
- for(int i=;i<=n;i++){
- int k=;
- for(int j=;j<=n;j++)
- if(u[j]&&minn[j]<minn[k])
- k=j;
- u[k]=false;
- for(int j=;j<=n;j++)
- if(u[j]&&g[k][j]<minn[j])
- minn[j]=g[k][j];
- }
- int total=;
- for(int i=;i<=n;i++)
- total+=minn[i];
- cout<<sum-total<<endl;
- return ;
- }
Prim
模板题:
洛谷P3366【模板】最小生成树:
题目链接:https://www.luogu.org/problemnew/show/P3366
思路:(Kruskal)
一道模板题,首先用一个结构体读入,然后初始化父节点,再按边权排序,然后用find函数分别找输入时的两个点的父节点,并判断其中一个是否是另一个的父亲,否则就进行合并,并将h+=a[i].l。(思路比较好理解)
- #include<cstdio>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- int h, f[];
- struct node{
- int x, y, l;
- } a[];
- inline bool cmp(node i, node j){
- return i.l < j.l;
- }
- inline int find(int x){
- if(x != f[x])
- f[x] = find(f[x]);
- return f[x];
- }
- int main(){
- int n, m;
- scanf("%d%d", &n, &m);
- for(int i = ; i <= n; i++){
- f[i] = i;
- }
- for(int i = ; i <= m; i++){
- scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].l);
- //h += a[i].l;
- }
- sort(a+, a+m+, cmp);
- for(int i = ; i <= m; i++){
- int r1 = find(a[i].x);
- int r2 = find(a[i].y);
- if(r1 != r2){
- f[r1] = r2;
- h += a[i].l;
- //h -= a[i].l;
- }
- }
- printf("%d", h);
- return ;
- }
AC代码
洛谷P2820 局域网:
题目链接:https://www.luogu.org/problemnew/show/P2820
思路:
首先这道题的问法就很模板:
很显然“f(i,j)表示i,j之间连接的畅通程度”即为i到j点的权值;“除去一些连线,使得网络中没有回路,并且被除去网线的Σf(i,j)最大”很显然是求最小生成树。但注意一个细节,它与最小生成树有所不同,它要求的是Σf(i,j)最大。
所以我们在最小生成树的模板上进行修改即可:读入时将所有的边权都加到h中。在判断父节点是否相同时,若不同,则将合并,并将合并的这条边的权值减掉即可。
- #include<cstdio>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- int f[], h;
- struct node{
- int x, y, l;
- } a[];
- inline bool cmp(node i, node j){
- return i.l < j.l;
- }
- inline int find(int x){
- if(x != f[x])
- f[x] = find(f[x]);
- return f[x];
- }
- int main(){
- int n, k;
- scanf("%d%d", &n, &k);
- for(int i = ; i <= n; i++){
- f[i] = i;
- }
- for(int i = ; i <= k; i++){
- scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].l);
- h += a[i].l;
- }
- sort(a+, a+k+, cmp);
- for(int i = ; i <= k; i++){
- int r1 = find(a[i].x);
- int r2 = find(a[i].y);
- if(r1 != r2){
- f[r1] = r2;
- h -= a[i].l;
- }
- }
- printf("%d", h);
- return ;
- }
AC代码
大概就是这样,个人认为Kruskal算法比Prim算法写起来简单并好理解....
最小生成树 & 洛谷P3366【模板】最小生成树 & 洛谷P2820 局域网的更多相关文章
- [洛谷P3366] [模板] 最小生成树
存个模板,顺便复习一下kruskal和prim. 题目传送门 kruskal 稀疏图上表现更优. 设点数为n,边数为m. 复杂度:O(mlogm). 先对所有边按照边权排序,初始化并查集的信息. 然后 ...
- P3366 (模板)最小生成树
2019-01-30 最小生成树基本算法 定义: 给定一个边带权的无向图G=(V,E),n=|V|,m=|E|,由V中全部n个定点和E中n-1条边构成的无向连通子图被称为G的一颗生成树. 边的权值之和 ...
- 洛谷P3366【模板】最小生成树-克鲁斯卡尔Kruskal算法详解附赠习题
链接 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M&l ...
- 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)
推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 洛谷 P2820 局域网
题目链接 https://www.luogu.org/problemnew/show/P2820 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内 ...
- 洛谷——P2820 局域网
P2820 局域网 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成 ...
- 模板<最小生成树>
转载 最小生成树浅谈 这里介绍最小生成树的两种方法:Prim和Kruskal. 两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣.Prim是以更新过的节点的连边找最小值,K ...
- POJ 2485 Highways【最小生成树最大权——简单模板】
链接: http://poj.org/problem?id=2485 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...
随机推荐
- OSCache简介
一.简介 Cache是一种用于提高系统响应速度.改善系统运行性能的技术.尤其是在Web应用中,通过缓存页面的输出结果,可以很显著的改善系统运行性能. OSCache标记库由OpenSymphony设计 ...
- android 拍照+拍照button 以及返回按钮布局
公司最近做一个项目拍照总是崩溃,所以决定自己写一个拍照的方法,在网上调研一番,写了一个简单demo,现共享如下 主要CameraActivity CameraActivity package com. ...
- linux加入windows域之完美方案
运行setup工具 认证配置 选择: “use winbind” “use kerberos” “use winbind authertication” 改为: 删除admin server 其余的改 ...
- 【bzoj1025】[SCOI2009]游戏
1025: [SCOI2009]游戏 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1987 Solved: 1289[Submit][Status] ...
- 代码查看import的类是出自哪个jar包的方法(转)
import java.security.ProtectionDomain; import java.security.CodeSource; public static void main(Stri ...
- Bootstrap 中的 aria-label 和 aria-labelledby 属性
这两个属性是为特殊网页阅读器设置的属性,在一些特殊设备上,当浏览到这样的内容设备会将内容读出来.是为了一些有视力障碍的人能够同样”浏览”网页而准备的. 转自http://blog.csdn.net/l ...
- Memcached 原理
memcached 是以一个守护进程的方式运行于一个服务器和多个服务器之间的,等待接受客户端的连接操作,客户端可以有各种语言编写.(例如PHP). php 在客户端与服务器建立连接以后,接下来的事情 ...
- CMD指令大全
命令提示符(CMD)是在OS / 2 , Windows CE与Windows NT平台为基础的操作系统(包括Windows 2000和XP中, Vista中,和Server 2003 )下的“MS- ...
- Part6-点亮指路灯_lesson1
1. 2.GPIO 查阅芯片手册:GPIO 代码: 3.外设基地址初始化 打开arm核手册, 基地址为0x70000000,去搜芯片手册6410, 把这个基地址告诉处理器,通过协处理器的cp15, 转 ...
- Entity Framework 6.0 Tutorials(7):DbSet.AddRange & DbSet.RemoveRange
DbSet.AddRange & DbSet.RemoveRange: DbSet in EF 6 has introduced new methods AddRange & Remo ...