题目大意

给出一个无向图,求出最小生成树,如果该图不连通,则输出orz。

概念

对于一个无向图,要求选出一些边,使得图上的每一个节点互相连通,且边权和最小。选出的边与节点形成的子图必然是颗树,这棵树叫做最小生成树。

Prim算法

原理

最小生成树中,除根节点外,每一个节点作为一个to节点与它相邻的边的边权(以后简称最小相邻边权)必然是最小的。

实现方法

邻接表

像Dijkstra一样,用一个priority_queue维护已访问的边,使得堆顶的边的边权是最小的。每次循环给出一条边cur,如果cur->to节点不在树中,则cur的权值便是cur->to的最小相邻边权。于是将cur->to节点纳入树中并记录结果。然后,由to节点扩展与它相邻的边e(e->to也不在树内)。

邻接矩阵

对于稠密图,用邻接表的方式还要维护一个堆,时间太慢。所以定义LowLen[u]为u节点目前搜索到的作为一个to节点与它相邻的边的边权的最小值。每次关于树内边的个数的cnt循环,将堆顶出来一条边改为枚举每一个不在树内的节点,找出LowLen[u]最小的u,此时的LowLen[u]便是u最小相邻边权。于是将u纳入树中,记录结果,然后通过u刷新与它相邻的树外节点的LowLen。

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
//#define test
#define LOOP(a, b) for(int a=1;(a)<=(b);a++)
using namespace std; const int MAX_NODE = 5010, MAX_EDGE = 200010 * 2, INF = 0x3f3f3f3f; struct Prim
{
struct Node;
struct Edge; struct Node
{
Edge *Head;
int Id;
bool Vis; Node()
{
Head = NULL;
Vis = false;
Id = 0;
}
}_nodes[MAX_NODE];
int _vCount;
Node *Start; struct Edge
{
Node *From, *To;
Edge *Next;
int Len, Id;
bool InGraph; Edge()
{
From = To = NULL;
Next = NULL;
Len = Id = 0;
InGraph = false;
} bool operator <(const Edge a)const
{
return Len > a.Len;
}
}_edges[MAX_EDGE];
int _eCount; void Init(int vCount, int sId)
{
memset(_nodes, 0, sizeof(_nodes));
memset(_edges, 0, sizeof(_edges));
_vCount = vCount;
_eCount = 0;
Start = sId + _nodes;
} Edge *NewEdge()
{
return ++_eCount + _edges;
} void AddEdge(Node *from, Node *to, int len)
{
Edge *e = NewEdge();
e->Id = _eCount;
e->From = from;
e->To = to;
e->Len = len;
e->Next = e->From->Head;
e->From->Head = e;
} void Build(int uId, int vId, int len)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
AddEdge(u, v, len);
AddEdge(v, u, len);
} int Proceed()
{
int ans = 0, cnt = 0;
priority_queue<Edge> q;
Start->Vis = true;//易忘点
cnt++;//易忘点
for (Edge *e = Start->Head; e; e = e->Next)
q.push(*e);
while (!q.empty() && cnt<_vCount)//易忘点:小于
{
Edge temp = q.top();
q.pop();
Edge *cur = temp.Id + _edges;
if (cur->To->Vis)
continue;
cur->To->Vis = true;
cur->InGraph = true;
ans += cur->Len;
cnt++;
for (Edge *e = cur->To->Head; e; e = e->Next)
if (!e->To->Vis)
q.push(*e);
}
return cnt == _vCount ? ans : -1;
}
}g; struct PrimMatrix
{
int Len[MAX_NODE][MAX_NODE];
bool InTree[MAX_NODE];
int LowLen[MAX_NODE];
int _vCount; void Init(int vCount)
{
memset(Len, INF, sizeof(Len));
_vCount = vCount;
} void Build(int u, int v, int dist)
{
Len[u][v] = Len[v][u] = min(Len[u][v], dist);
} int Proceed()
{
int cnt = 1, ans = 0;
memset(InTree, false, sizeof(InTree));
memset(LowLen, INF, sizeof(LowLen));
InTree[1] = true;//易忘点
LOOP(v, _vCount)
LowLen[v] = Len[1][v];
LOOP(i, _vCount)
{
int u, lowLen = INF;
LOOP(j, _vCount)
{
if (!InTree[j] && LowLen[j] < lowLen)
{
lowLen = LowLen[j];
u = j;
}
}
if (lowLen == INF)
break;
cnt++;
ans += lowLen;
InTree[u] = true;
LOOP(v, _vCount)//注意从此往后就不用lowLen了。lowLen就是为了确定u用的。
if (!InTree[v] && Len[u][v] < LowLen[v])
LowLen[v] = Len[u][v];
}
return cnt == _vCount ? ans : -1;
}
}g1; int main() {
int totNode, totEdge, uId, vId, len;
scanf("%d%d", &totNode, &totEdge);
g1.Init(totNode);
while (totEdge--)
{
scanf("%d%d%d", &uId, &vId, &len);
g1.Build(uId, vId, len);
}
int ans = g1.Proceed();
if (ans == -1)
printf("orz\n");
else
printf("%d\n", ans);
return 0;
}

  

luogu3366 【模板】 最小生成树 Prim的更多相关文章

  1. 模板——最小生成树prim算法&&向前星理解

    通过最小生成树(prim)和最短路径优化引出的向前星存图,时至今日才彻底明白了.. head[i]存储的是父节点为i引出的最后一条边的编号, next负责把head[i]也就是i作为父节点的所有边连接 ...

  2. poj1861 最小生成树 prim &amp; kruskal

    // poj1861 最小生成树 prim & kruskal // // 一个水题,为的仅仅是回味一下模板.日后好有个照顾不是 #include <cstdio> #includ ...

  3. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。

    //归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...

  4. 邻接矩阵c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)

    matrix.c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include < ...

  5. 最小生成树Prim算法(邻接矩阵和邻接表)

    最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...

  6. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  7. 最小生成树Prim

    首先解释什么是最小生成树,最小生成树是指在一张图中找出一棵树,任意两点的距离已经是最短的了. 算法要点: 1.用book数组存放访问过的节点. 2.用dis数组保存对应下标的点到树的最近距离,这里要注 ...

  8. 最小生成树—prim算法

    最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...

  9. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  10. 最小生成树 Prim Kruskal

    layout: post title: 最小生成树 Prim Kruskal date: 2017-04-29 tag: 数据结构和算法 --- 目录 TOC {:toc} 最小生成树Minimum ...

随机推荐

  1. 另一种压缩图片的方法---Machine learning 之 PCA(Principle Component Analysis)

    PCA最主要的用途是用来减少特征向量的数目,N个特征向量 减小到 K个特征向量.如果为了可视化,k可以使3 或者 2.这样可以加速算法的学习速度. PCA用来压缩图像同一有效. 具体方式以及原理在gi ...

  2. vue vuex初学基础 常见错误解决方式

    前端界面使用篇 vue生命周期初始化事件 http://www.cnblogs.com/lily1010/p/5830946.html 常见错误篇 1 Newline required at end ...

  3. Beta冲刺-星期三

    这个作业属于哪个课程  <课程的链接>            这个作业要求在哪里 <作业要求的链接> 团队名称 Three cobblers 这个作业的目标 剩余任务预估,分配 ...

  4. AndroidStudio怎样导入library项目库

    先打开一个Project,然后将libraryr的项目作为module进行导入: File菜单->import module菜单 以上只是导入进来,还没有作为与project真正有效的一部分.需 ...

  5. OpenVX

    OpenVX openvx  1. 编译 尝试编译openvx_sample,下载相关代码. 下载的sample code直接使用make可以生成libopenvx.so. 使用python Buil ...

  6. 查看SqlServer连接所使用的端口号

    最近一个项目里用到了一个插件,在配置时发现连接数据库使用的是JDBC,输入URL时用到了端口号.印象中在使用Sqlserver时貌似没有提到端口号,在网上查阅了一下,记录下来省的忘了 方法是通过内置的 ...

  7. SAP computer之program counter

    Program counter The program is stored in memory with the first instruction at binary address 0000, t ...

  8. SQL Server存储过程作业(二)

    阶段1:练习——统计某类型客房的入住客人人数 需求说明 使用存储过程统计在指定类型的客房入住客人的总人数 提示: 存储过程的输入参数是指定的客房类型名称 USE Hotel GO --阶段1:查询入住 ...

  9. 【sqli-labs】 less18 POST - Header Injection - Uagent field - Error based (基于错误的用户代理,头部POST注入)

    这次username和password都进行了输入校验 但是ip和uagent没有校验 当我们用admin admin登陆成功后,就会一条插入语句 由于程序无条件的信任了浏览器的header信息,那么 ...

  10. 微信小程序 请求超时处理

    1.在app.json加入一句 "networkTimeout": { "request": 10000 } 设置超时时间,单位毫秒 2.请求 wx.reque ...