The Unique MST
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 23180   Accepted: 8235

Description

Given a connected undirected graph, tell if its minimum spanning tree is unique. 



Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties: 

1. V' = V. 

2. T is connected and acyclic. 



Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all
the edges in E'. 

Input

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a
triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.

Sample Input

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 Output

3
Not Unique!

Source

对于最小生成树(能够用kruskal和prime算法求得,在这里我是用kruskal求得,假设不会请自己百度。),边的权值的和最小称为最小生成树。

而次小生成树就是除了最小生成树外的最小生成树。并且全部的次小生成树都是通过最小生成树的换边得到的。

所以难点就是怎样换边。

对于怎样换边:

1.先求出最小生成树,值为x。

2.一一枚举加入不在生成树上的边(这时候一定形成了一个环)

3.寻找环上的(最小生成树上的边)权值最大值与你所加入不在生成树上的边的权值比較,所得到的差值为min。

因为是一一枚举加入边,min有多个,求出最小的哪一个,所以次小生成树就为x+min。

昨天尽管把这道题A了,但是看到讨论区的測试数据发现自己又一个没有过,然而却AC了。然后今天起床就来研究研究。

发现我的程序是在找最大值。但是假设一个环有分支,它还会去找分支里面的最大值。于是就又优化了一下。

用的优先队列。

先附上第一次做的代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct node
{
int a,b,cost;
}c[10005];
int fa[105],tree[105][105],vis[10005],vis_tree[105];//vis数组是对m对数据的标记vis_tree是对最小生成树标记
int n,m,max1;
bool cmp(node x,node y)
{
if(x.cost<y.cost)
return true;
else
return false;
}
int find(int x)//寻找根
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void sec_tree(int a,int b)//查找生成树某条边的最大值(我在这里做的是错误的。假设形成的环有分支,也会查找)
{
vis_tree[a]=1;
if(a==b)
return ;
for(int i=1;i<=n;i++)
if(tree[a][i]&&!vis_tree[i])
{
if(max1<tree[a][i])
max1=tree[a][i];
sec_tree(i,b);
}
}
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
memset(&c,0,sizeof(&c));
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost);
sort(c,c+m,cmp);
int sum=0;
for(int i=0;i<m;i++)//kruskal算法求最小生成树
{
int x=find(c[i].a);
int y=find(c[i].b);
if(x!=y)
{
fa[x]=y,sum+=c[i].cost;
tree[x][y]=tree[y][x]=c[i].cost;
vis[i]=1;
}
}
int flag=0;
for(int i=0;i<m;i++)
{
if(!vis[i])//不在生成树中的边和形成的环的最大值比較。假设相等,MST不唯一
{
max1=-1;
memset(vis_tree,0,sizeof(vis_tree));
sec_tree(c[i].a,c[i].b);
if(max1==c[i].cost)
{
flag=1;
break;
}
}
}
if(!flag)
printf("%d\n",sum);
else
printf("Not Unique!\n");
}
}

这是优化后的代码。凝视和上面一样。就一个地方不同:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
struct node1
{
int a,b,cost;
friend bool operator<(node1 x,node1 y )
{
return x.cost<y.cost;
}
};
priority_queue<node1>s;
struct node
{
int a,b,cost;
}c[10005];
int fa[105],tree[105][105],vis[10005],vis_tree[105];
int n,m,max1,flag1;
bool cmp1(node x,node y)
{
if(x.cost<y.cost)
return true;
else
return false;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void sec_tree(int a,int b)
{
node1 temp;
vis_tree[a]=1;
if(a==b)//假设找到a=b,标记一下
{
flag1=1;
}
for(int i=1;i<=n;i++)
if(tree[a][i]&&!vis_tree[i])
{
temp.a=a,temp.b=i,temp.cost=tree[a][i];
s.push(temp);
if(!flag1)//就是在这里和上面不同,假设找不到a=b,那么就把曾经的恢复
s.pop(),vis_tree[i]=0,sec_tree(i,b);
}
}
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
memset(&c,0,sizeof(&c));
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost);
sort(c,c+m,cmp1);
int sum=0;
for(int i=0;i<m;i++)
{
int x=find(c[i].a);
int y=find(c[i].b);
if(x!=y)
{
fa[x]=y,sum+=c[i].cost;
tree[x][y]=tree[y][x]=c[i].cost;
vis[i]=1;
}
}
int flag=0;
for(int i=0;i<m;i++)
{
if(!vis[i])
{
int flag1=0;
while(!s.empty())
s.pop();
memset(vis_tree,0,sizeof(vis_tree));
sec_tree(c[i].a,c[i].b);
node1 temp;
temp=s.top();
if(temp.cost==c[i].cost)
{
flag=1;
break;
}
}
}
if(!flag)
printf("%d\n",sum);
else
printf("Not Unique!\n");
}
}

poj1679 The Unique MST(判定次小生成树)的更多相关文章

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

    http://poj.org/problem?id=1679 Description Given a connected undirected graph, tell if its minimum s ...

  2. POJ1679 The Unique MST 【次小生成树】

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

  3. POJ1679 The Unique MST【次小生成树】

    题意: 判断最小生成树是否唯一. 思路: 首先求出最小生成树,记录现在这个最小生成树上所有的边,然后通过取消其中一条边,找到这两点上其他的边形成一棵新的生成树,求其权值,通过枚举所有可能,通过这些权值 ...

  4. POJ1679 The Unique MST(次小生成树)

    可以依次枚举MST上的各条边并删去再求最小生成树,如果结果和第一次求的一样,那就是最小生成树不唯一. 用prim算法,时间复杂度O(n^3). #include<cstdio> #incl ...

  5. The Unique MST(次小生成树)

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22335   Accepted: 7922 Description Give ...

  6. POJ1679The Unique MST(次小生成树)

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

  7. poj 1679 The Unique MST【次小生成树】

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

  8. POJ 1679:The Unique MST(次小生成树&amp;&amp;Kruskal)

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

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

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

  10. POJ 1679 The Unique MST (次小生成树)题解

    题意:构成MST是否唯一 思路: 问最小生成树是否唯一.我们可以先用Prim找到一棵最小生成树,然后保存好MST中任意两个点i到j的这条路径中的最大边的权值Max[i][j],如果我们能找到一条边满足 ...

随机推荐

  1. 【LeetCode-面试算法经典-Java实现】【05-Longest Palindromic Substring(最大回文字符串)】

    背景 近期開始研究算法,于是在leetcode上做算法题,第五题Longest Palindromic Substring便是关于回文子串的. 什么是回文字串 回文字符串是指将该字符串前后颠倒之后和该 ...

  2. 9.9递归和动态规划(六)——打印n对括号的所有有效组合(即左右括号正确配对)

    /**  * 功能:打印n对括号的所有有效组合(即左右括号正确配对). */ 两种方法: 方法一: /** * 思路:在括号的最前面或者原有的每对括号中面插入一对括号. 至于其它任何位置.比方字符串的 ...

  3. vmware虚拟机Windows 2003上网问题

    近期须要在Windows 2003 上面做点操作,于是安装虚拟机玩了一下,发现并不能上网,最后的解决的方法是: 卸载IE增强的安全配置 控制面板→加入或删除程序→加入/删除Windows组件" ...

  4. 用YourAPP开发网络状态提醒应用

    如今的通信真是方便,走到哪里都有网络.Wifi的利用已经到了很普及的程度.即使走到没有wifi信号的地方,利用手机信号也能上网.(若是连手机信号都没有,那就没办法了) 智能手机的使用也大慷慨面了各个年 ...

  5. Android学习笔记之图像颜色处理(ColorMatrix)

    对图像进行颜色方面的处理,通过使用颜色矩阵(ColorMatrix)来实现.从而可以达到很多特效如黑白老照片.泛黄旧照片等等. 1.颜色矩阵(ColorMatrix) 这里有详细的介绍:http:// ...

  6. OpenCV —— HighGUI

    分为:硬件相关部分,文件部分以及图形用户接口部分 创建窗口 —— cvNamedWindow 若设置成 CV_WINDOW_AUTOSIZE 窗口大小会随着图像的载入而根据图像大小调整,用户没办法手动 ...

  7. 【2017 Multi-University Training Contest - Team 3】RXD and math

    [Link]: [Description] [Solution] 发现1010mod(109+7)=999999937; 猜测答案是nk 写个快速幂; 注意对底数先取模; [NumberOf WA] ...

  8. linux6.0系统如何安装portmap

    因为在6.0的系统里,portmap已经改名了.在Redhat或CentOS5中可以使用 service portmap start启动服务,然后在启动nfs服务,实现挂载. 6里面可是试试 serv ...

  9. 【OC学习-8】存取器方法?getter和setter?事实上就是赋值和返回值的两种函数

    我们在声明类的时候,有实例变量+方法(函数),这些实例变量假设默认的话都是protected类型,一般无法直接訪问.更别提赋值和调用了,所以就产生了两种函数,getter函数就是可以返回实例变量的值, ...

  10. thinkphp5空控制器和空操作

    thinkphp5空控制器和空操作 一.总结 1.空控制器和空操作用:空控制器和空操作都是为了防止网站上的用户恶意输入,网站上线的话必须加上, 2.空操作:空操作就是在一般的控制器里面加上一个 _em ...