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. [51Nod]NOIP2018提高组省一冲奖班模测训练(三) 题解

    链接 A.Anan的派对 题意:Anan想举办一个派对.Anan的朋友总共有 n 人.第i个人如果参加派对会得到 \(c_i\) 的快乐值,除他自己外每多一个人参加他会减少 \(d_i\) 的快乐值. ...

  2. javascript变量类型及作用域

    javascript变量类型及作用域 一.简介 变量类型 ECMAScript变量可能包含两种不同类型的数据值:基本类型和引用类型. 基本类型 基本类型指的是简单的数据段,5种基本数据类型:undef ...

  3. zoj 1119 / poj 1523 SPF (典型例题 求割点 Tarjan 算法)

    poj : http://poj.org/problem?id=1523 如果无向图中一个点 u 为割点 则u 或者是具有两个及以上子女的深度优先生成树的根,或者虽然不是一个根,但是它有一个子女 w, ...

  4. 39.C语言操作数据库

    一.准备工作: sqlite3工具集:链接:https://pan.baidu.com/s/1mjufXZa 密码:2ui7 安装步骤: 打开如下文件夹,找到sqlite3.dll,并放入系统目录 2 ...

  5. solr简介

    Solr 是什么? Solr它是一种开放源码的.基于 Lucene Java 的搜索服务器,易于加入到 Web 应用程序中. Solr 提供了层面搜索(就是统计).命中醒目显示并且支持多种输出格式(包 ...

  6. 【基础篇】EditText的一些属性设置

    设置EditText的背景颜色  private test_editText=null; test_editText= (EditText) findViewById(R.id.EditTextInp ...

  7. 小程序block总结

    小程序block总结 1.block并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性. 2.因为 wx:if 是一个控制属性,需要将它添加到一个标签上.如果要一次性判断多个 ...

  8. ES6--基础语法(一)

    一.支持环境:node.js完全支持,标准浏览器完全支持.二.测试环境: chrome下需要在script标签的最先开始的地方需要添加"use strict". firefox下需 ...

  9. 小米开源文件管理器MiCodeFileExplorer-源码研究(4)-文件操作工具类FileOperationHelper

    文件操作是非常通用的,注释都写在源代码中了,不多说~需要特别说明的是,任务的异步执行和IOperationProgressListener.拷贝和删除等操作,是比较费时的,采用了异步执行的方式~ An ...

  10. JavaScript入门:003—JS中的变量

    编程语言都是同样的,JS中也是有变量的.首先JS的变量是区分大写和小写的,这个须要注意.比方number和Number是不同的变量.无论是经常使用类型的,还是对象类型,比方 Object obj和Ob ...