题意:求解最小生成树的权值是否唯一,即要我们求次小生成树的权值
两种方法求最小生成树,一种用prim算法, 一种用kruskal算法

一:用prim算法

对于给定的图,我们可以证明,次小生成树可以由最小生成树变换一边得到。 那么我们可以如下求给定图的次小生成树。首先,我们用prime算法求出图的最小生成树, 在这个过程中记录每条边是否用过,以及两个点之间最短路径上的最大权值F[i,j]

F[i,j]可以如此求得,当加入点u的时候,并且u的父结点是v 那么对于已经在生成树中的节点x F[x,u] = max(F[x,v],w[u][v]),那么我么就可以用Prime算法一样的时间复杂度来求出图的次小生成树。

参考链接:http://blog.csdn.net/lyg_wangyushi/article/details/4371734

#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <string>
#include <queue>
using namespace std; const int INF=0x3f3f3f3f;
int n,m;
int ans1,ans2;
int w[][];
int dis[];
int pre[];
int vis[];
int use[][]; //use[i][j]=1表示边(i,j)在最小生成树里,=0则不在
int f[][]; //f[u][v]表示结点u到结点v的最短路径上边的最大值(即最大边的值)
vector<int> son[]; //son[i]存储的是与i连接的端点 void init() {
memset(pre,,sizeof(pre));
memset(dis,INF,sizeof(dis));
memset(vis,,sizeof(vis));
memset(f,,sizeof(f));
memset(use,,sizeof(use));
}
//求最小生成树
int solve_MST() {
init();
vector<int> node;
int s=,counts=,ans=,tmp,k;
dis[s]=;
pre[s]=s; node.push_back(s); //一开始dis都赋值为INF,所以为了减少一点点遍历的时间,node存储的是dis不为INF的点
while() {
tmp=INF;
for(int i=; i<node.size(); i++) {
int v=node[i];
if(!vis[v]&& dis[v]<tmp) {
tmp=dis[v];
k=v; //k即为在没有进入最小生成树的点中到树的距离(dis[k])最小的点。
}
}
if(tmp==INF)
break;
use[k][pre[k]]=use[pre[k]][k]=; for(int i=;i<=n;i++){
if(vis[i]){
f[i][k]=f[k][i]=max(f[i][pre[k]],w[k][pre[k]]);
f[i][k]=f[k][i]=max(f[pre[k]][i],w[k][pre[k]]);
}
}
ans+=tmp;
vis[k]=; for(int i=; i<son[k].size(); i++) {
int v=son[k][i];
if(!vis[v] && w[k][v]<dis[v]) {
dis[v]=w[k][v];
pre[v]=k;
node.push_back(v);
}
}
}
return ans; }
//求次小生成树
int second_MST(int ans){
int second=INF;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(!use[i][j] && ans-f[i][j]+w[i][j]<second){
second=ans-f[i][j]+w[i][j];
}
}
}
return second;
}
int main() {
int t,a,b,c;
scanf("%d",&t);
for(int i=;i<=t;i++){
scanf("%d%d",&n,&m);
memset(w,INF,sizeof(w)); for(int i=;i<;i++){
son[i].clear();
}
for(int j=;j<=m;j++){
scanf("%d%d%d",&a,&b,&c);
w[a][b]=w[b][a]=c;
son[a].push_back(b);
son[b].push_back(a);
}
ans1=solve_MST();
ans2=second_MST(ans1);
if(ans1==ans2)
printf("Not Unique!\n");
else
printf("%d\n",ans1);
}
return ;
}

二:用kruskal算法

枚举删除最小生成树上的边,再求最小生成树,即总共求n-1次最小生成树,取其中最小值。

这道题如果用该方法,有一点要注意,不然的话会一直WA。

我做这道题的时候一直wrong answer的原因是因为, 可能求出的次小生成树正好等于最小生成树的总权值,但是它不连通,即边的个数小于n-1

可以试试这个测试数据:

1

6 7

1 3 1

1 2 2

2 3 3

3 4 0

4 5 4

4 6 5

5 6 6

结果是 12

就是说,如果次小生成树不连通,且最小生成树中被你删的边恰好是权值为0的情况, 这样权值总和仍相等,但不满足生成树的要求。

#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <string> using namespace std; int t,n,m,cost,x,y,w; //n个节点,m条边
int ansMST,secondMST;
int numOfEdge; struct Edge{
int u,v;
int cost; bool operator < (const Edge& tmp) const
{
return cost< tmp.cost;
} }edge[],MSTedge[]; struct UF{
int father[]; void unit(){
for(int i=;i<=n;i++){
father[i]=i;
}
} int find_root(int x){
if(father[x]!=x)
father[x]=find_root(father[x]);
return father[x];
} void Union(int fa,int fb){
father[fb]=fa;
}
}uf; //求最小生成树
int solveMST(){
int counts=;
int ans=;
//int index=0;
for(int i=;i<m;i++){
int u=edge[i].u;
int v=edge[i].v;
int fu=uf.find_root(u);
int fv=uf.find_root(v);
if(counts>=n-){
break;
} if(fu!=fv){
ans+=edge[i].cost;
uf.Union(fu,fv);
MSTedge[counts].u=u;
MSTedge[counts].v=v;
MSTedge[counts].cost=edge[i].cost;
counts++;
}
}
return ans;
}
/**
a、b表示最小生成树中删去的那条边
这里是删去(a,b)边后,求最小生成树
*/
int solve(int a,int b){
int counts=;
int ans=;
for(int i=;i<m;i++){
int u=edge[i].u;
int v=edge[i].v;
int fu=uf.find_root(u);
int fv=uf.find_root(v);
if((u==a && v==b)||(u==b && v==a))
continue;
if(counts>=n-){
break;
}
if(fu!=fv){
ans+=edge[i].cost;
counts++;
uf.Union(fu,fv);
}
}
numOfEdge=counts;
return ans;
} int main()
{
scanf("%d",&t); for(int i=;i<=t;i++){
scanf("%d%d",&n,&m);
for(int j=;j<m;j++){
scanf("%d%d%d",&x,&y,&w);
edge[j].u=x;
edge[j].v=y;
edge[j].cost=w;
}
sort(edge,edge+m); uf.unit();
ansMST=solveMST(); //最小生成树的总权值
secondMST=; //次小生成树的总权值
//枚举,取最小值
for(int j=;j<n-;j++){
int u=MSTedge[j].u;
int v=MSTedge[j].v;
uf.unit();
int total=solve(u,v);
//如果它的总权值小于目前的secondMST,并且边的个数也正好为n-1
if(total<secondMST && numOfEdge==n-){
secondMST=total;
}
} if(secondMST==ansMST)
printf("Not Unique!\n");
else
printf("%d\n",ansMST);
}
return ;
}

POJ 1679 The Unique MST(次小生成树)的更多相关文章

  1. POJ 1679 The Unique MST (次小生成树)

    题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...

  2. POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)

    题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...

  3. POJ 1679 The Unique MST (次小生成树kruskal算法)

    The Unique MST 时间限制: 10 Sec  内存限制: 128 MB提交: 25  解决: 10[提交][状态][讨论版] 题目描述 Given a connected undirect ...

  4. poj 1679 The Unique MST (次小生成树(sec_mst)【kruskal】)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 35999   Accepted: 13145 ...

  5. poj 1679 The Unique MST 【次小生成树】【模板】

    题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...

  6. POJ 1679 The Unique MST 【最小生成树/次小生成树模板】

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22668   Accepted: 8038 D ...

  7. POJ1679 The Unique MST —— 次小生成树

    题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total S ...

  8. poj 1679 The Unique MST

    题目连接 http://poj.org/problem?id=1679 The Unique MST Description Given a connected undirected graph, t ...

  9. poj 1679 The Unique MST(唯一的最小生成树)

    http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submis ...

  10. poj 1679 The Unique MST (判定最小生成树是否唯一)

    题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total S ...

随机推荐

  1. COUNT(*),count(1),COUNT(ALL expression),COUNT(DISTINCT expression) BY Group by

    select column_2,count(column_2) as 'count(column_2)' ,count(column_1) as 'count(column_1)' ,count(*) ...

  2. Microsoft SqlServer2008技术内幕:T-Sql语言基础-读书笔记-单表查询SELECT语句元素

    1.select语句逻辑处理顺序: FORM WHERE GROUP BY HAVING SELECT OVER DISTINCT TOP ORDER BY 总结: 2.FORM子句的表名称应该带上数 ...

  3. ode.js 版本控制 nvm 和 n 使用 及 nvm 重启终端失效的解决方法

    今天的话题包括2个部分 node.js 下使用 nvm 或者 n 来进行版本控制 nvm 安装node.js 版本后,重启终端 node , npm 环境变量失效 第一部分 用什么来管理 node.j ...

  4. 安装Oracle11g时,检测到系统的主 IP 地址是 DHCP 分配的地址

    检查完成.此次检查的总体结果为: 失败 <<<< 问题: 安装检测到系统的主 IP 地址是 DHCP 分配的地址. 建议案: Oracle 支持在具有 DHCP 分配的 IP ...

  5. Eclipse常用快捷键使用

    Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能,能够大大提高开发效率.Eclipse中有如下一些和编辑相关的快捷键.     1. [ALT+/]     此快捷键为用户编辑的好帮手 ...

  6. 利用js排序html表格

    在web前端开发中会遇到排序等功能,当然也可以用服务器端来排序,今天我做一个笔记,怎么用js来实现这些复杂的功能呢. 在学习这个之前一定得用html dom jquery 的知识,要不没有办法看明白的 ...

  7. centos下安装nagios

    摘要Nagios是一款开源的免费网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等. Nagios是一款开源的免费网络监视工具,能有效监控Wind ...

  8. HTML5七大优势“逼宫”APP

    HTML5颠覆了PC互联网的格局,优化了移动互联网的体验,接下来几年,HTML5将颠覆原生App世界. 跨平台: 在多屏年代,开发者的痛苦指数非常高,人人都期盼HTML5能扮演救星.多套代码.不同技术 ...

  9. 服务器 IIS 发布网站 支持下载 apk 和 ipa

    方法/步骤   1 打开IIS服务管理器,找到服务器,右键-属性,打开IIS服务属性: 2 单击MIME类型下的"MIME类型"按钮,打开MIME类型设置窗口: 3 单击" ...

  10. 30.DDR2问题2_local_init_done为什么没拉高?

    按照初始化时序,在200us时,mem_clk时钟稳定,开始初始化设置,设置完后,会产生一个初始化完成标志,local_init_done会拉高,没有拉高,可能有以下几个原因: 1.确认DDR2 IP ...