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. MongoDB + node-mongoskin简单演示样例

    特点 无模式 MongoDB 中的每一条文档,都是一个 JSON 对象,因此你无需提前定义一个集合的结构,集合中的每一个文档也能够有不同的结构. 异步写入 MongoDB 默认全部的写操作都是『不安全 ...

  2. zoj 2778 - Triangular N-Queens Problem

    题目:在三角形的棋盘上放n皇后问题. 分析:找规律题目.依照题目的输出,能够看出构造法则: 先填奇数,后填偶数.以下我们仅仅要证明这样的构造的存在性就可以. 解法:先给出集体构造方法,从(1.n-f( ...

  3. 56.lambda表达式与绑定以及伪函数和绑定

    #include <iostream> #include <functional> using namespace std; using namespace std::plac ...

  4. Kinect 开发 —— Kinect for windows SDK

    开发 —— 基本的SDK和Windows 编程技巧(彩色图像视频流,深度图像视频流的采集,骨骼跟踪,音频处理,语音识别API) 深度数据,就是Kinect的精髓和灵魂,很多问题都转换为深度图像的模式识 ...

  5. JavaScript翻译成Java

    这两天公司有一个需求,将一段加密的JavaScript代码转换为JAVA版. JavaScript中的某一段代码: 前期查看了整个JavaScript代码,发现代码中,方法里面嵌套方法,各种不合规的变 ...

  6. ST和LCA和无根树连接

    #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm& ...

  7. dp之完全背包 hdu--2159一维数组做法

    #include <iostream>#include <stdio.h>#include <string.h>using namespace std;int ma ...

  8. Go语言核心之美 1.5-作用域

    变量的作用域是指程序代码中能够有效使用这个变量的范围. 不要将作用域和生命期混在一起. 作用域是代码中的一块区域,是一个编译期的属性:生命期是程序执行期间变量存活的时间段.在此时间段内,变量能够被程序 ...

  9. Android JSON数据解析(GSON方式)

    要创建和解析JSON数据,也可以使用GSON来完成.GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.使用GSON,可以很容易的将一串JSON数据转换为一个Jav ...

  10. CSS min-height不能解决垂直外边距合并问题

    垂直外边距合并有一种情况是嵌套元素的垂直外边距合并,当父级元素没有设定外边距时,在顶部或者底部边缘的子元素的垂直外边距就会和父级的合并,导致父级也有了“隐形”的垂直外边距. 当父级元素的min-hei ...