题意:

给你一张无向图,让你判断三种情况:1.不是连通图(无法形成生成树)2.只能生成唯一的生成树 3.能生成的生成树不唯一(有次小生成树),这种情况要求出次小生成树的边权值和。

思路:

比较常见的次小生成树做法:先求出最小生成树,再依次使用不在最小生成树上的边与最小生成树连接,连接后必然出现且仅出现一个环(由于生成树上的任意两点之间都有唯一的一条路径,且图中所有的点都在生成树上),将这条边与环上除了这条边权值最大的边替换,就形成了新的生成树,在不断尝试新边的过程中维护一个最小的生成树的边权值和即是次小生成树的边权值和。

可以发现生成的环形成的路径即是两个端点与它们的LCA(最近公共祖先)的路径,所以可以用求LCA的办法顺便记录路径中边权的最大值。

代码:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
typedef long long ll;
using namespace std; const int N=1e2+; struct edge {
int id;
int from;
int to;
int val;
}E[N<<]; struct cmp {
bool operator()(edge a,edge b) {
return a.val>b.val;
}
}; int fir[N],nex[N<<],cnt;
int pre[N],dis[N],dep[N];
bool vis[N],used[N<<];
int T=,t,n,m,cost; void init() {
memset(fir,-,sizeof(fir));
cost=cnt=;
} void connect(int from,int to,int val,int id) {
E[cnt]=(edge){id,from,to,val};
nex[cnt]=fir[from];
fir[from]=cnt++;
E[cnt]=(edge){id,to,from,val};
nex[cnt]=fir[to];
fir[to]=cnt++;
} bool prim() {
int node=;//记录生成树上的点的数量。
memset(vis,false,sizeof(vis));
memset(used,false,sizeof(used));
priority_queue <edge,vector <edge>,cmp> Q;
Q.push((edge){-,,,});
dep[]=;
while(!Q.empty()) {
edge q=Q.top();
Q.pop();
if(vis[q.to]) continue;
vis[q.to]=true;
cost+=q.val; node++;
pre[q.to]=q.from;
dis[q.to]=q.val;
dep[q.to]=dep[q.from]+;//在求最小生成树的过程中顺便记录生成树上的点的深度以及父节点、与父节点连接的边的权值。
used[q.id]=true;//记录哪些边在最小生成树上,到时在求次小生成树的过程中跳过这些边。
for(int i=fir[q.to];i!=-;i=nex[i]) {
int to=E[i].to;
if(!vis[to]) Q.push(E[i]);
}
}
if(node<n) return false;//生成树上的点少于n,说明不是连通图,无法形成最小生成树。
return true;
} int lca(int x,int y) {
int MAX=;
if(dep[x]>dep[y]) swap(x,y);
while(dep[y]>dep[x]) {
MAX=max(MAX,dis[y]);
y=pre[y];
}
while(x!=y) {
MAX=max(MAX,dis[y]);
y=pre[y];
MAX=max(MAX,dis[x]);
x=pre[x];
}
return MAX;
} void solve() {
bool flag=false;
int second=2e9;
for(int i=;i<cnt;i+=) {
if(used[E[i].id]) continue;
flag=true;
second=min(second,cost+E[i].val-lca(E[i].from,E[i].to));
}
if(flag) printf("Case #%d : %d\n",++T,second);//若除了最小生成树上的边以外没有剩下的边,那么没有次小生成树。
else printf("Case #%d : No second way\n",++T);
} int main() {
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
init();
for(int i=;i<=m;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
connect(x,y,z,i);
}
if(!prim()) {
printf("Case #%d : No way\n",++T); continue;
}
solve();
}
return ;
}

UVA - 10462 Is There A Second Way Left?的更多相关文章

  1. UVA 10462 Is There A Second Way Left? 次小生成树

    模板题 #include <iostream> #include <algorithm> #include <cstdio> #include <cstdli ...

  2. UVA 10462 Is There A Second Way Left?(次小生成树&Prim&Kruskal)题解

    思路: Prim: 这道题目中有重边 Prim可以先加一个sec数组来保存重边的次小边,这样不会影响到最小生成树,在算次小生成树时要同时判断次小边(不需判断是否在MST中) Kruskal: Krus ...

  3. UVA 10462 —— Is There A Second Way Left?——————【最小生成树、kruskal、重边】

    Nasa, being the most talented programmer of his time, can’t think things to be so simple. Recently a ...

  4. UVA 10462 Is There A Second Way Left? (次小生成树+kruskal)

    题目大意: Nasa应邻居们的要求,决定用一个网络把大家链接在一起.给出v个点,e条可行路线,每条路线分别是x连接到y需要花费w. 1:如果不存在最小生成树,输出“No way”. 2:如果不存在次小 ...

  5. UVA - 10462-Is There A Second Way Left? Kruskal求次小生成树

    UVA - 10462 题意: 求次小生成树的模板题,这道题因为有重边的存在,所以用kruskal求比较好. #include <iostream> #include <cstdio ...

  6. [kuangbin带你飞]专题八 生成树 - 次小生成树部分

    百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...

  7. KUANGBIN带你飞

    KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题    //201 ...

  8. kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

    第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一 ...

  9. [kuangbin带你飞]专题1-23题目清单总结

    [kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...

随机推荐

  1. Hibernate实现分页查询

    分页查询就是把数据库中某张表的记录数进行分页查询,在做分页查询时会有一个Page类,下面是一个Page类,我对其做了详细的注解: 1 package com.entity; 2 /** 3 * @au ...

  2. VirtualBox虚拟机安装

    目录 安装前准备 1.开始安装,安装很简单,直接上图 2.设置全局路径,这里主要是方便以后创建虚拟机的时候不用每次都去选择存放位置,默认是存放到C盘 安装前准备 系统:Windows 10 专业版 软 ...

  3. C# 元组

    Tuple<,); Console.WriteLine(t.Item1); Console.WriteLine(t.Item2); C#7 可以使用圆括号声明一个元组: (); Console. ...

  4. AJAX数据传输

    AJAX = Asynchronous JavaScript and XML(异步的Javascript和XML) AJAX最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页 ...

  5. VisualStudioAddIn2017.vsix的下载安装和使用

    本加载项是用于Visual Studio的,下载以后按照如下步骤进行安装: 完全退出Visual Studio 把下载了的文件解压缩,会产生一个VisualStudioAddIn2017.vsix文件 ...

  6. php获取mysql大小

      查看指定数据库大小:  SELECT sum(DATA_LENGTH)+sum(INDEX_LENGTH) FROM information_schema.TABLES where    TABL ...

  7. python学习笔记(8)迭代器和生成器

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

  8. 如何使用iTunes制作iPhone铃声

    新版iTunes(iTunes11)推出以后,界面上发生了一些改变,给人带来一种面貌一新的感觉,但也给许多朋友带来一些操作上的不太适应.下面就大家比较关心的iPhone的铃声制作方法,我在iTunes ...

  9. Mac环境下安装Redis

    转自:http://www.jianshu.com/p/6b5eca8d908b -安装 下载安装包 redis-3.0.7.tar.gz 官网地址:http://redis.io/download ...

  10. HDU 5978 To begin or not to begin

    题目:HDU 5978 To begin or not to begin 思路: 题目意思是说:给出n个黑球,一个红球,拿到红球的人胜利.如果先手有优势的输出 1 ,没有优势的输出 2 ,机会均等则输 ...