关于最小生成树(并查集)prime和kruskal
适合对并查集有一定理解的人. 新手可能看不懂吧....
并查集简单点说就是将相关的2个数字联系起来
比如
房子 1 2 3 4 5 6
能通向的房子 2 3 4 5 6 1
主要 建立并查集的 函数结构 模板(一般不变除非加权--最好能理解)
for(int i=0;i<n;i++)
flag[i]=i; //标记数组初始化以方便寻根
1 int find(int x) X相当于1
{
int r=x,t; r代表的是根节点
while(x!=flag[x]) 如果 没有找到 就继续追到根为止
x=flag[x];
while(r!=x)
{ //这里是相关优化 有个定义叫做秩就是类似于楼的层数 秩越低 你就越容易从楼顶走到楼底 将秩全部变成1即一层楼
t=flag[r];
flag[r]=x;
r=t;
}
return x;
}
主要就是这个
最小生成树中 keruskai()
核心思想: 将所有元素按照某一标志 排序 然后从最前开始一次检索寻根如果
二者没有相同的根就说明他们是第一次相互关联 然后把它们的权加到value上
举例 : 你要把3个房间打通来让 别人 可以去任意房间..
这些房间没有房顶你能飞到任意房间去砸墙 但是他们的关联情况不同并且 花费的费用也不同
你要使他们的费用最低
1. A B 10万元
2. B C 20万元
3. A C 30万元 你可以
1,2 30
1,3 40
2,3 50
显然选择 1,2
就用上面的kruskal
排序后 先是 a-b 判断是否有相同根(打通?)没有 就打通 10万元 然后
b-c 判断是否有相同的根 没有就打通 然后继续判断
a-c 判断已经打通了 跳过...
(当然也可以加一个sum统计打通情况3个房间 2个通道就行 打通一次sum++;当sum=n-1直接跳过节省时间)
最小生成树中prime();
简单点说就是用一个二维数组记录用坐标对应 他的权(距离/价值) 然后从第第一个起点扫描和他链接的其他点
中的权值并加入一个新的数组 找到权值最小的点就是所求的,标记他,然后从他权值最小对应的点开始扫描和他相关联的点
如果比之前 存权呢个数组小就更新为新的值(重点重点重点----)具体看例题代码的
例题 poj 1861 [ http://poj.org/problem?id=1861 ]
2种解法(kruskal(克鲁斯卡尔)这个过了 ,prime 表示没过(输出感觉没有问题..)
建议..用kruskal
据说简单的快,复杂的prime快) 上代码
kruskal()
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int flag[],ans,p[],n,m,maxx,num;
int find(int a)
{
int r=a,tmp;
while(r!=p[r])
r=p[r];
while(a!=r)
{
tmp=p[a];
p[a]=r;
a=tmp;
}
return r;
}
struct nood
{
int x,y,w;
} pp[];
int cmp(nood xx,nood yy)
{
return xx.w<yy.w;
}
int kruskal()
{
sort(pp,pp+m,cmp);
memset(flag,,sizeof(flag));
num=maxx=;
ans=;
for(int i=; i<=n; i++)
p[i]=i;
for(int i=; i<m; i++)
{
if(num==n-)
break;
int xxx=find(pp[i].x);
int yyy=find(pp[i].y);
if(xxx!=yyy)
{
p[xxx]=yyy;
flag[ans++]=pp[i].x;
flag[ans++]=pp[i].y;
maxx=max(pp[i].w,maxx);
num++;
}
}
return ;
}
int main()
{
cin>>n>>m;
for(int i=; i<m; i++)
cin>>pp[i].x>>pp[i].y>>pp[i].w;
kruskal();
cout<<maxx<<endl<<num<<endl;
for(int i=; i<ans; i++)
{
cout<<flag[i];
if(i%==)
cout<<endl;
else
cout<<" ";
}
return ;
} /* 一种输出
1 3
1 3
2 3
2 4 输入数据
4 6
1 2 1
1 3 1
1 4 2
2 3 1
3 4 1
2 4 1 */
prime();
不知道为啥WR
代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#define maxx 1200
using namespace std;
int n,m,pp[maxx][maxx],value[maxx],flag[maxx],maxpath,num,a[maxx],maxxx;
int prime()
{
int ans=;
maxpath=maxxx=num=;
memset(value,,sizeof(value));
memset(a,,sizeof(a));
memset(flag,,sizeof(flag));
//初始化相关参数
for(int i=; i<=n; i++)//以 1 为起始点更新权值数组
{
if(pp[][i]!=maxx)
value[i]=pp[][i];
else
value[i]=maxx;
flag[i]=;
}
flag[]=;//标记用过了..
//寻找剩下的 边
for(int i=; i<=n; i++)
{
int k,min=maxx;//k作为下次扫描的点
for(int j=; j<=n; j++) //依次扫描寻找与k即i相关联的 最小权值
{
if(flag[j]!=&&min>value[j])
{
min=value[j];
k=j;
}
}
//更新相关参数
maxpath=max(maxpath,value[k]);
maxxx+=value[k];
a[ans++]=flag[k];
a[ans++]=k;
num++;
flag[k]=;//标记
//更新与上面相关的对应的权值
//(当这些权值小于上一次的就替换~重点!)
//就这个实现了当有2个出发点的时候
//首出发点 相对应的小于第二个的 选择了首出发点
for(int j=; j<=n; j++)
{
if(flag[j]!=&&pp[k][j]<value[j]/*此处有无等号*/)
{
value[j]=pp[k][j];
flag[j]=k;
}
}
}
cout<<maxpath<<endl<<maxxx<<endl;
for(int i=; i<ans; i++)
{
cout<<a[i];
if(i%!=)
cout<<" ";
else
cout<<endl;
}
return ;
}
int main()
{
//freopen("a1.txt","r",stdin);
//freopen("a11.txt","w",stdout);
cin>>n>>m;
//读入关联信息及其权值
memset(pp,maxx,sizeof(pp));
for(int i=; i<=m; i++)
{
int x,y;
cin>>x>>y;
cin>>pp[x][y];
}
prime();
return ;
}
或许会改....有空再说吧
关于最小生成树(并查集)prime和kruskal的更多相关文章
- UVA 1395 苗条的生成树(最小生成树+并查集)
苗条的生成树 紫书P358 这题最后坑了我20分钟,怎么想都对了啊,为什么就wa了呢,最后才发现,是并查集的编号搞错了. 题目编号从1开始,我并查集编号从0开始 = = 图论这种题真的要记住啊!!题目 ...
- CSP 201703-4 地铁修建【最小生成树+并查集】
问题描述 试题编号: 201703-4 试题名称: 地铁修建 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市 ...
- (最小生成树 并查集)P1111 修复公路 洛谷
题目背景 A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车.政府派人修复这些公路. 题目描述 给出A地区的村庄数N,和公路数M,公路是双向的.并告诉你每条公路的连着哪两个村庄,并告诉你什么时 ...
- 【BZOJ4144】[AMPPZ2014]Petrol(最短路+最小生成树+并查集)
Description 给定一个n个点.m条边的带权无向图,其中有s个点是加油站. 每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满. q次询问,每次给出x,y,b,表示出发点是 ...
- bzoj 3559: [Ctsc2014]图的分割【最小生成树+并查集】
读题两小时系列-- 在读懂题意之后,发现M(c)就是c这块最大权割边也就是的最小生成树的最大权边的权值,所以整个问题都可以在MST的过程中解决(M和c都是跟着并查集变的) 不过不是真的最小生成树,是合 ...
- Luogu P1195/P1892 口袋的天空/BOI团伙 【最小生成树/并查集】By cellur925
其实这俩题挺水的,团伙拿下了一血,但是感觉还是写一下博客比较好x. 一.团伙 题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是 ...
- 复习--最小生成树&&并查集
我个人比较喜欢Kruskal算法,所以就把这个方法写了一下,但过不了洛谷,70分. 思路是先全读入,再排序,一条一条加边.运用并查集. #include<iostream> #includ ...
- Regional Changchun Online--Travel(最小生成树&& 并查集)
Travel Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total S ...
- UOJ14 UER #1 DZY Loves Graph(最小生成树+并查集)
显然可以用可持久化并查集实现.考虑更简单的做法.如果没有撤销操作,用带撤销并查集暴力模拟即可,复杂度显然可以均摊.加上撤销操作,删除操作的复杂度不再能均摊,但注意到我们在删除时就可以知道他会不会被撤销 ...
随机推荐
- 解决git反复输入密码的问题
打开git命令面板 cd到项目根目录 $ git config --global credential.helper store然后只输入一次密码,后面就不需要了
- 安装酷痞到IIS7.x共用80端口Windows(64位)系统下运行多个酷痞
需求: 1.酷痞直接运行的模式是自宿主运行.由于win系统一般都由iis提供多个网站服务,并首先占用了80端口,如果想酷痞可以直接通过主机头和iis共用80端口会出现这种运行模式的需求. 以下是实现方 ...
- springmvc的ModelMap,前台取值
利用 ${user.id}或者‘${user.id}’都是可以直接获取到的,不过前提是在jsp页面的script脚本中,而在引用的js文件中是不可以使用的,因为${}是jsp的el标签. 利用 ${u ...
- SAS 对数据的拼接与串接
SAS 对数据的拼接与串接 使用SAS对数据进行串接.合并.更新与修改. 1. 数据集的纵向串接 数据集的纵向串接指的是,将两个或者多个数据集首尾相连,形成 一个新的数据集. 对数据集的纵向串接可以通 ...
- 拷贝JAR包
package com.cici; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; i ...
- collections标准库
collections标准库 之前Python的第三方库用的一直很舒服,现在突然发现标准库也有collections这样的神器,可以补充list.set.dict以外的应用 1. namedtuple ...
- Java虚拟机一 运行时数据区(栈、堆、方法区等)
Java虚拟机的内存管理主要分两点:内存分配以及内存回收.· 一.内存分配图: 注: 所占区域的大小与实际的内存大小比例并无直接关系. 解读: 1.如图,分成两种颜色的内存区域,其中蓝色的是线程隔离的 ...
- Java当中的IO一
1.IO操作的目标 什么是IO操作的目标? 输入: 从数据源当中读取数据 输出: 将数据写入到数据目的地当中 有数据进入到程序当中,这个过程就可以被叫做输入 流:即在数据源与程序之间建立的传输通道 2 ...
- __x__(32)0908第五天__Photoshop的基本操作
1. 设置 Photoshop 的单位为 像素px 2. 标尺 显示与隐藏 Ctrl + r 3. 放大与缩小 Ctrl + 1 放大到100% Ctrl + 0 适应屏幕 Alt + ...
- windows系统 phpstudy2018 配置阿里云https最简单的流程!
一.从阿里去下载ssl文件放到C:\phpStudy\PHPTutorial\Apache\conf\cert 二.首先phpstudy开户php_openssl扩展,具体如下图 一般网上的教程,都要 ...