次小生成树学习+例题 poj 1679 The Unique MST
次小生成树学习:
顾名思义,次小生成树,就是将图的所有生成树排序后,权值第二小的生成树。
次小生成树的朴素求法是很好想的,即首先求出最小生成树,之后枚举最小生成树中的所有边,将当前枚举的边“禁止使用”,在这基础之上再求最小生成树,将所有边枚举之后的结果取最小值,那就是次小生成树。这个算法简单暴力,但是可想而知的复杂度是比较大的,在图是稠密图的时候,复杂度接近O(n^3)。在规模较大的时候不建议使用。
另一个推荐的求法:在添加最小生成树的边之外的边时,会形成环,这个时候,把在这个环中,且在最小生成树中的边给去掉,这时候就形成了另一个生成树。如何实现这个算法的呢?实际上,对于两个点u,v,我们遍历最小生成树,找出u到v的边中的最大权值的边,用一个数组maxn[u][v]保存起来。当我们往最小生成树中加边时,就直接用w - max[u][v] + 当前添加边的权值,这个式子计算出此时生成树的权值之和。那么maxn[u][v]这个数组是如何求得呢?嗯,bfs,即广度优先搜索,对每一个点都遍历一次生成树,每次更新的值都是当前点到其他点的权值。之后就枚举不在生成树的边进行计算,把每次的结果都保存下来,取最小的,就是次小生成树啦。(或许第k小生成树可以这么求?)这个算法的复杂度为O(n^2)。
例题:
https://vjudge.net/problem/POJ-1679
题意:
这题问的是最小生成树是否唯一。
思路:
那么很显然的,如果说最小生成树不唯一的话,那么最小生成树与次小生成树的权值肯定相等,因为对于在最小生成树中的边来说,至少存在一条不在其中的边,与在其中的边的权值相等,这样才满足不唯一,所以只需要求出次小生成树,判断其与最小生成树是否相等就可以了。
PS:通过这题还学会了用邻接链表表示图,用vector很方便的,就是把以每个点为起点的边搞到一起就ok。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std; struct node
{
int x,y,w;
} e[]; struct ord
{
int p,dis;
}; vector<node> v[]; int par[];
int maxn[][]; bool used[],vis[]; void init(int n)
{
for (int i = ;i <= n;i++)
par[i] = i;
} int fin(int x)
{
if (x == par[x]) return x;
else return par[x] = fin(par[x]);
} void unit(int x,int y)
{
x = fin(x);
y = fin(y); if (x != y) par[x] = y;
} bool cmp(node aa,node bb)
{
return aa.w < bb.w;
} void adde(int x,int y,int dis)
{
node t;
t.x = x;
t.y = y;
t.w = dis;
v[x].push_back(t);
} void bfs(int k)
{
memset(used,,sizeof(used)); ord now,nex; now.p = k;now.dis = ;
used[k] = true; queue<ord> qq; while (!qq.empty()) qq.pop(); qq.push(now); while (!qq.empty())
{
//printf("dsfsd\n");
ord t = qq.front();qq.pop(); int x = t.p,tmaxn = t.dis; for (int i = ;i < v[x].size();i++)
{
node tt = v[x][i]; nex.dis = tt.w;nex.p = tt.y; if (!used[nex.p])
{
if (tmaxn > nex.dis) nex.dis = tmaxn;
used[nex.p] = true;
maxn[k][nex.p] = nex.dis;
qq.push(nex);
}
}
}
} int main()
{
int t; scanf("%d",&t); while (t--)
{
int n,m; scanf("%d%d",&n,&m); init(n); memset(v,,sizeof(v));
memset(vis,,sizeof(vis));
memset(used,,sizeof(used)); for (int i = ;i < m;i++)
{
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
} sort(e,e+m,cmp); int ans = ; for (int i = ;i < m;i++)
{
int x = e[i].x,y = e[i].y; if (fin(x) == fin(y)) continue; unit(x,y); vis[i] = true; ans += e[i].w; adde(x,y,e[i].w);
adde(y,x,e[i].w);
} for (int i = ;i <= n;i++)
{
bfs(i);
} int minn = ; for (int i = ;i < m;i++)
{
if (!vis[i])
{
int tans = ans;
int x = e[i].x,y = e[i].y; tans -= maxn[x][y]; tans += e[i].w; if (tans < minn) minn = tans;
} } if (minn == ans) printf("Not Unique!\n");
else printf("%d\n",ans);
} return ;
}
次小生成树学习+例题 poj 1679 The Unique MST的更多相关文章
- poj 1679 The Unique MST 【次小生成树】【模板】
题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...
- poj 1679 The Unique MST 【次小生成树+100的小数据量】
题目地址:http://poj.org/problem?id=1679 2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2 Sample Outpu ...
- poj 1679 The Unique MST
题目连接 http://poj.org/problem?id=1679 The Unique MST Description Given a connected undirected graph, t ...
- poj 1679 The Unique MST(唯一的最小生成树)
http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submis ...
- poj 1679 The Unique MST (判定最小生成树是否唯一)
题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total S ...
- POJ 1679 The Unique MST (次小生成树)
题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...
- POJ 1679 The Unique MST:次小生成树【倍增】
题目链接:http://poj.org/problem?id=1679 题意: 给你一个图,问你这个图的最小生成树是否唯一. 题解: 求这个图的最小生成树和次小生成树.如果相等,则说明不唯一. 次小生 ...
- POJ 1679 The Unique MST(次小生成树)
题意:求解最小生成树的权值是否唯一,即要我们求次小生成树的权值两种方法求最小生成树,一种用prim算法, 一种用kruskal算法 一:用prim算法 对于给定的图,我们可以证明,次小生成树可以由最小 ...
- poj 1679 The Unique MST【次小生成树】
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24034 Accepted: 8535 D ...
随机推荐
- SQL SERVER大话存储结构(6)_数据库数据文件
数据库文件有两大类:数据文件跟日志文件,每一个数据库至少各有一个数据文件或者日志文件,数据文件用来存储数据,日志文件用来存储数据库的事务修改情况,可用于恢复数据库使用. 这里分 ...
- Chrome 开发者工具断点调试(视频教程)
很多人不了解 Chrome Dev Tools (开发者工具)的使用方法和技巧. 其中很多技能,无论是前端开发从业者,还是普通用户,了解一些还是对日常很有帮助的. 本猿定期录制.甚至根据您的需求来订制 ...
- C#之out修饰符、ref修饰符、params修饰符的简单介绍
一.out修饰符 1.调用一个带有输出参数的方法也需要使用out 修饰符,但是作为输出变量传递的本地变量在将他们作为输出变量传递前不需要赋值(因为调用后会改变或丢失),编译器允 许 ...
- mysql之 mysql 5.6不停机主从搭建(一主一从)
环境说明:版本 version 5.6.25-log 主库ip: 10.219.24.25从库ip:10.219.24.22os 版本: centos 6.7已安装热备软件:xtrabackup 防火 ...
- sock
头和尾基本用来做校验, 不是拿来做边界的. 头+类型+长度+数据+尾, 这种结构就可以. 拆包就是: 检验头, 然后拆出类型+长度, 然后根据长度拆数据, 然后检验尾巴.
- sublime 新手代码提示
有提示的 你按 table 试试这就是按过的结果 是不是很方便这是按后的效果 是不是很方便 下面是各种简写效果html <html></html> ...
- Mac下将ISO写入U盘镜像
在Mac下面如果想做一个启动U盘,确实不如windows下那么方便,Windows下面有ultraiso+王涛,Mac下面测可以用下面的办法. 打开磁盘工具 插入U盘,并在磁盘工具里面找到U盘,把它卸 ...
- JavaScript对象之document对象
DOM对象之document对象 DOM对象:当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. 打开网页后,首先 ...
- 检查服务器是否开启GD库
1.把以下代码复制到记事本中并保存成A.php<?phpOb_end_flush();header ("Content-type: image/png");$im = @im ...
- java源码学习(四)ArrayList
ArrayList ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下, ...