POJ 1679 判最小生成树的不唯一性 或 利用次小生成树求解
题目大意:
给定一个无向图,寻找它的最小生成树,如果仅有一种最小生成树,输出所有边的和,否则输出unique!
根据kruscal原理来说,每次不断取尽可能小的边不断添加入最小生成树中,那么可知如果所有边的长度都不相同,那么kruscal取得过程必然只有一种情况,由小到大
所以要是存在多种情况的最小生成树,那么必然是存在相同的边
初始将所有相同的边进行标记,生成第一次最小生成树后,不断去除其中带标记的边,然后再计算最小生成树,判断能否得到同样的答案,如果可以,说明不止一种情况
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 105
int fa[N] , same[N] , first[N] , k;
int rec[N] , amo;//rec[]记录MST中含有相同长度边的位置,amo记录其数量
struct Edge{
int x,y,d,next,flag;
bool same;
bool operator<(const Edge &m) const{
return d<m.d;
}
}e[N*N]; int find_head(int x)
{
while(fa[x]!=x) x=fa[x];
return x;
} bool Union(int x,int y)
{
int fa_x = find_head(x);
int fa_y = find_head(y);
fa[fa_x] = fa_y;
return fa_x == fa_y;
} void add_edge(int x, int y , int d)
{
e[k].x=x , e[k].y=y , e[k].d=d , e[k].flag= , e[k].next=first[x];
e[k].same = false;
first[x] = k++;
} int cal_MST(int n , int flag)
{
int ans = , cnt=;
for(int i= ; i<=n ; i++) fa[i]=i;
for(int i= ; i<k ; i++){
if(e[i].flag==){
if(!Union(e[i].x , e[i].y)){
ans+=e[i].d;
if(e[i].same && flag){
rec[amo++] = i;
}
cnt++;
if(cnt == n-) break;
}
}
}
return ans;
} int main()
{
int T;
scanf("%d" , &T);
while(T--)
{
int n , m , x , y , d;
scanf("%d%d" , &n , &m);
k=;
memset(first , - , sizeof(first));
for(int i= ; i<m ; i++){
scanf("%d%d%d" , &x , &y , &d);
add_edge(x , y , d);
} sort(e , e+k);
//对存在相同边的边进行标记
for(int i= ; i<k ; i++)
if(e[i].d == e[i-].d) e[i].same=e[i-].same=true;
amo = ;
int ans = cal_MST(n , );
bool is_unique = true;
for(int i= ; i<amo ; i++){
e[rec[i]].flag = ;
int t=cal_MST(n , );
if(t == ans){
is_unique=false;
break;
}
e[rec[i]].flag = ;
}
if(is_unique) printf("%d\n" , ans);
else puts("Not Unique!");
}
return ;
}
上面那个明显复杂度比较高
我们可以求解出次小生成树的值与最小生成树的值进行比较判断是否唯一
先求出最小生成树,用二维数组mx[][]记录最小生成树上两个点之间路径上最长边的长度
然后找到每一条不属于最小生成树的边u,v ,这样可以与原最小生成树中u->v的路径形成一个环,那么最后需要在环中删去一条最长边,那么只要不断得到这个差值的最小值
用最小生成树的值减去他就可以了
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define N 105
const int INF = 0x3f3f3f3f;
int mx[N][N] , w[N][N];
int n , m;
int d[N] , connect[N];
bool vis[N][N] , in[N]; int prim()
{
int ret = ;
memset(vis , , sizeof(vis));
memset(connect , , sizeof(connect));
memset(in , , sizeof(in));
memset(mx , , sizeof(mx));
d[] = INF , in[] = true;
for(int i= ; i<=n ; i++)
if(w[][i]>=){
d[i] = w[][i];
connect[i] = ;
}
else d[i] = INF; for(int i= ; i<n ; i++){
int minn = INF , index = ;
for(int j= ; j<=n ; j++){
if(in[j]) continue;
if(d[j]<minn) minn=d[j] , index=j;
}
int u = connect[index];
d[index] = INF , vis[index][u] = vis[u][index] = true;
mx[index][u] = mx[u][index] = minn , in[index] = true , ret+=minn;
for(int j= ; j<=n ; j++){
if(in[j] || w[index][j]<) continue;
if(w[index][j]<d[j]) d[j] = w[index][j] , connect[j] = index;
}
for(int j= ; j<=n ; j++){
if(!in[j]) continue;
mx[j][index] = mx[index][j] = max(mx[index][j] , max(mx[index][u] , minn));
}
}
return ret;
} int sec_mst(int mst)
{
int del = INF;
for(int i= ; i<=n ; i++){
for(int j=i+ ; j<=n ; j++){
if(!vis[i][j] && w[i][j]>=){
del = min(del , mx[i][j]-w[i][j]);
}
}
}
return mst-del;
} int main()
{
// freopen("in.txt" , "r" , stdin);
int T;
scanf("%d" , &T);
while(T--)
{
scanf("%d%d" , &n , &m);
memset(w , - , sizeof(w));
int u , v , wei;
while(m--){
scanf("%d%d%d" , &u , &v , &wei);
w[u][v] = w[v][u] = wei;
}
int ret = prim();
int sec = sec_mst(ret);
if(ret == sec) puts("Not Unique!");
else printf("%d\n" , ret);
}
return ;
}
POJ 1679 判最小生成树的不唯一性 或 利用次小生成树求解的更多相关文章
- poj 1679 判断最小生成树是否唯一
/* 只需判断等效边和必选边的个数和n-1的关系即可 */ #include<stdio.h> #include<stdlib.h> #define N 110 struct ...
- POJ 1679 The Unique MST(判断最小生成树是否唯一)
题目链接: http://poj.org/problem?id=1679 Description Given a connected undirected graph, tell if its min ...
- POJ 1679 The Unique MST (最小生成树)
The Unique MST 题目链接: http://acm.hust.edu.cn/vjudge/contest/124434#problem/J Description Given a conn ...
- POJ 1679 The Unique MST(次小生成树)
题意:求解最小生成树的权值是否唯一,即要我们求次小生成树的权值两种方法求最小生成树,一种用prim算法, 一种用kruskal算法 一:用prim算法 对于给定的图,我们可以证明,次小生成树可以由最小 ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- POJ 1679 The Unique 次最小生成树 MST
http://poj.org/problem?id=1679 题目大意: 给你一些点,判断MST(最小生成树)是否唯一. 思路: 以前做过这题,不过写的是O(n^3)的,今天学了一招O(n^2)的,哈 ...
- (poj)1679 The Unique MST 求最小生成树是否唯一 (求次小生成树与最小生成树是否一样)
Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definit ...
- POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)
题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...
随机推荐
- MyEclipse中Tomcat对应JVM的参数配置
MyEclipse中Tomcat对应JVM的参数配置: -Xmx512M -Xms256M -XX:MaxPermSize=256m
- Ubuntu下编译安装MySQL5.7
tar zxvf mysql-5.7.14.tar.gz cd mysql-5.7.14 第一步: cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql/ \ ...
- android开发学习——Mina框架
Apache Mina Server 是一个网络通信应用框架,对socket进行了封装. http://www.cnblogs.com/moonandstar08/p/5475766.html htt ...
- SQL Server 编程入门
一.T—SQL 的组成 1.DML(数据操作语言 Data Manipulation Language) 查询.插入.删除和修改数据库中的数据.SELECT.INSERT.UPDATE.DELETE ...
- 面相切面编程AOP以及在Unity中的实现
一.AOP概念 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.它是 ...
- mybatis的mapper.xml文件细节
- 简单工厂模式-Java篇
简单工厂模式就是考虑如何实例化对象的问题,就是说到底要实例化谁,将来会不会增加实例化对象,比如计算器类中增加开根元素,应该考虑用一个单独的类来创造实例的过程,这就是工厂.下面将利用计算器类举例,解释简 ...
- 一个完整的http请求分析
Request URL:http://localhost:8080/test.jhtmlRequest Method:POSTStatus Code:200 OKRemote Address:[::1 ...
- com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "FileSize"
请求阿里云的OSS接口图片信息,返回json格式的数据,通过ObjectMapper将json转为Image对象时候报错转换失败 将json转对象的代码: String jsonStr = " ...
- php防止页面刷新代码
//代理IP直接退出 empty($_SERVER['HTTP_VIA']) or exit('Access Denied'); //防止快速刷新 session_start(); $seconds ...