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 ...
随机推荐
- 随机带权选取文件中一行 分类: linux c/c++ 2014-06-02 00:11 344人阅读 评论(0) 收藏
本程序实现从文件中随即选取一行,每行被选中的概率与改行长度成正比. 程序用一次遍历,实现带权随机选取. 算法:假设第i行权重wi(i=1...n).读取到文件第i行时,以概率wi/(w1+w2+... ...
- 多功能Markdown编辑器MarkdownPad 2的下载、安装和初步使用步骤(图文详解)(博主推荐)
不多说,直接上干货! MarkdownPad 是什么? 一.MarkdownPad 2的下载 http://markdownpad.com/download/markdownpad2-setup. ...
- android开发学习 ------- 【转】Gradle相关
一直在用AndroidStudio,但是对于其Gradle了解的很少. 推荐 http://www.jianshu.com/p/9df3c3b6067a 觉得说的很棒!
- jquery 实现 点击把数据移动右侧 点击再次移回到左侧
2018年第一发 希望新的一年和大家一下学习更多知识 JS://把数据左边挪到了右边,再从右边移动回来function moveOption(e1, e2){ $("#" ...
- javascript之input获取的时间减1秒&&t时间恢复
将输入得到的时间减少1秒:20:00:00 ——— 19:59:59 方法一:普通时间转换 endDateMap(date){ var h = new Date(date).getHours ...
- Java编程思想总结笔记Chapter 5
初始化和清理是涉及安全的两个问题.本章简单的介绍“垃圾回收器”及初始化知识. 第五章 初始化与清理 目录:5.1 用构造器确保初始化5.2 方法重载5.3 默认构造器5.4 this关键字5.5 清 ...
- "码代码"微信号今日上线,为互联网同仁提供最前沿咨询
"码代码"微信号今日上线 关注即有好礼相送 三月,春意浓浓的日子,三月,属于女人的日子,而今天...... “2014年天空成人放送大赏”于5日晚举办颁奖典礼,“年度最佳AV女优” ...
- Objective-C 是动态语言
Objective-C 的动态性是由 runtime 相关的库赋予的. 当然其他语言也完全可以运行在一个 Runtime 库上而获得动态性,由于多数高级语言的诞生都对应着一种编译器,因此将编译器的特性 ...
- 修改phpadmin中的默认超时时间
登录后1440秒未活动后总是自动退出,一天还要登录多次,终于有时间来解决这个问题了,感觉是session超时,结果在网上search了下,找到解决办法啦,哈哈哈,在此做个笔记: phpmyadmin在 ...
- docker 入门学习
一 : docker 安装(linux-centos7) 安装docker要求 1.docker只支持在64位cup架构计算机上运行,目前不支持32位cup. 2.建议系统的linux内核版本在3.1 ...