POJ 1679 The Unique MST(次小生成树)
题意:求解最小生成树的权值是否唯一,即要我们求次小生成树的权值
两种方法求最小生成树,一种用prim算法, 一种用kruskal算法
一:用prim算法
对于给定的图,我们可以证明,次小生成树可以由最小生成树变换一边得到。 那么我们可以如下求给定图的次小生成树。首先,我们用prime算法求出图的最小生成树, 在这个过程中记录每条边是否用过,以及两个点之间最短路径上的最大权值F[i,j]
F[i,j]可以如此求得,当加入点u的时候,并且u的父结点是v 那么对于已经在生成树中的节点x F[x,u] = max(F[x,v],w[u][v]),那么我么就可以用Prime算法一样的时间复杂度来求出图的次小生成树。
参考链接:http://blog.csdn.net/lyg_wangyushi/article/details/4371734
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <string>
#include <queue>
using namespace std; const int INF=0x3f3f3f3f;
int n,m;
int ans1,ans2;
int w[][];
int dis[];
int pre[];
int vis[];
int use[][]; //use[i][j]=1表示边(i,j)在最小生成树里,=0则不在
int f[][]; //f[u][v]表示结点u到结点v的最短路径上边的最大值(即最大边的值)
vector<int> son[]; //son[i]存储的是与i连接的端点 void init() {
memset(pre,,sizeof(pre));
memset(dis,INF,sizeof(dis));
memset(vis,,sizeof(vis));
memset(f,,sizeof(f));
memset(use,,sizeof(use));
}
//求最小生成树
int solve_MST() {
init();
vector<int> node;
int s=,counts=,ans=,tmp,k;
dis[s]=;
pre[s]=s; node.push_back(s); //一开始dis都赋值为INF,所以为了减少一点点遍历的时间,node存储的是dis不为INF的点
while() {
tmp=INF;
for(int i=; i<node.size(); i++) {
int v=node[i];
if(!vis[v]&& dis[v]<tmp) {
tmp=dis[v];
k=v; //k即为在没有进入最小生成树的点中到树的距离(dis[k])最小的点。
}
}
if(tmp==INF)
break;
use[k][pre[k]]=use[pre[k]][k]=; for(int i=;i<=n;i++){
if(vis[i]){
f[i][k]=f[k][i]=max(f[i][pre[k]],w[k][pre[k]]);
f[i][k]=f[k][i]=max(f[pre[k]][i],w[k][pre[k]]);
}
}
ans+=tmp;
vis[k]=; for(int i=; i<son[k].size(); i++) {
int v=son[k][i];
if(!vis[v] && w[k][v]<dis[v]) {
dis[v]=w[k][v];
pre[v]=k;
node.push_back(v);
}
}
}
return ans; }
//求次小生成树
int second_MST(int ans){
int second=INF;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(!use[i][j] && ans-f[i][j]+w[i][j]<second){
second=ans-f[i][j]+w[i][j];
}
}
}
return second;
}
int main() {
int t,a,b,c;
scanf("%d",&t);
for(int i=;i<=t;i++){
scanf("%d%d",&n,&m);
memset(w,INF,sizeof(w)); for(int i=;i<;i++){
son[i].clear();
}
for(int j=;j<=m;j++){
scanf("%d%d%d",&a,&b,&c);
w[a][b]=w[b][a]=c;
son[a].push_back(b);
son[b].push_back(a);
}
ans1=solve_MST();
ans2=second_MST(ans1);
if(ans1==ans2)
printf("Not Unique!\n");
else
printf("%d\n",ans1);
}
return ;
}
二:用kruskal算法
枚举删除最小生成树上的边,再求最小生成树,即总共求n-1次最小生成树,取其中最小值。
这道题如果用该方法,有一点要注意,不然的话会一直WA。
我做这道题的时候一直wrong answer的原因是因为, 可能求出的次小生成树正好等于最小生成树的总权值,但是它不连通,即边的个数小于n-1
可以试试这个测试数据:
1
6 7
1 3 1
1 2 2
2 3 3
3 4 0
4 5 4
4 6 5
5 6 6
结果是 12
就是说,如果次小生成树不连通,且最小生成树中被你删的边恰好是权值为0的情况, 这样权值总和仍相等,但不满足生成树的要求。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <string> using namespace std; int t,n,m,cost,x,y,w; //n个节点,m条边
int ansMST,secondMST;
int numOfEdge; struct Edge{
int u,v;
int cost; bool operator < (const Edge& tmp) const
{
return cost< tmp.cost;
} }edge[],MSTedge[]; struct UF{
int father[]; void unit(){
for(int i=;i<=n;i++){
father[i]=i;
}
} int find_root(int x){
if(father[x]!=x)
father[x]=find_root(father[x]);
return father[x];
} void Union(int fa,int fb){
father[fb]=fa;
}
}uf; //求最小生成树
int solveMST(){
int counts=;
int ans=;
//int index=0;
for(int i=;i<m;i++){
int u=edge[i].u;
int v=edge[i].v;
int fu=uf.find_root(u);
int fv=uf.find_root(v);
if(counts>=n-){
break;
} if(fu!=fv){
ans+=edge[i].cost;
uf.Union(fu,fv);
MSTedge[counts].u=u;
MSTedge[counts].v=v;
MSTedge[counts].cost=edge[i].cost;
counts++;
}
}
return ans;
}
/**
a、b表示最小生成树中删去的那条边
这里是删去(a,b)边后,求最小生成树
*/
int solve(int a,int b){
int counts=;
int ans=;
for(int i=;i<m;i++){
int u=edge[i].u;
int v=edge[i].v;
int fu=uf.find_root(u);
int fv=uf.find_root(v);
if((u==a && v==b)||(u==b && v==a))
continue;
if(counts>=n-){
break;
}
if(fu!=fv){
ans+=edge[i].cost;
counts++;
uf.Union(fu,fv);
}
}
numOfEdge=counts;
return ans;
} int main()
{
scanf("%d",&t); for(int i=;i<=t;i++){
scanf("%d%d",&n,&m);
for(int j=;j<m;j++){
scanf("%d%d%d",&x,&y,&w);
edge[j].u=x;
edge[j].v=y;
edge[j].cost=w;
}
sort(edge,edge+m); uf.unit();
ansMST=solveMST(); //最小生成树的总权值
secondMST=; //次小生成树的总权值
//枚举,取最小值
for(int j=;j<n-;j++){
int u=MSTedge[j].u;
int v=MSTedge[j].v;
uf.unit();
int total=solve(u,v);
//如果它的总权值小于目前的secondMST,并且边的个数也正好为n-1
if(total<secondMST && numOfEdge==n-){
secondMST=total;
}
} if(secondMST==ansMST)
printf("Not Unique!\n");
else
printf("%d\n",ansMST);
}
return ;
}
POJ 1679 The Unique MST(次小生成树)的更多相关文章
- POJ 1679 The Unique MST (次小生成树)
题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...
- POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)
题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...
- POJ 1679 The Unique MST (次小生成树kruskal算法)
The Unique MST 时间限制: 10 Sec 内存限制: 128 MB提交: 25 解决: 10[提交][状态][讨论版] 题目描述 Given a connected undirect ...
- poj 1679 The Unique MST (次小生成树(sec_mst)【kruskal】)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 35999 Accepted: 13145 ...
- poj 1679 The Unique MST 【次小生成树】【模板】
题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...
- POJ 1679 The Unique MST 【最小生成树/次小生成树模板】
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22668 Accepted: 8038 D ...
- POJ1679 The Unique MST —— 次小生成树
题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total S ...
- poj 1679 The Unique MST
题目连接 http://poj.org/problem?id=1679 The Unique MST Description Given a connected undirected graph, t ...
- poj 1679 The Unique MST(唯一的最小生成树)
http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submis ...
- poj 1679 The Unique MST (判定最小生成树是否唯一)
题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total S ...
随机推荐
- this的使用方法
当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this.this是指向对象本身的一个指针.this只和特定的对象关联,而不和类关联,同一个类的不同对 ...
- linux系统设置-防火墙
基础知识 Linux系统内核内建了netfilter防火墙机制.Netfilter(数据包过滤机制),所谓的数据包过滤,就是分析进入主机的网络数据包,将数据包的头部数据提取出来进行分析,以决该连接为放 ...
- django-pagination的使用
1.安装django-pagination 2.将文件夹pagination复制到项目的根目录下 3.修改settings: 1.将 'pagination.middleware.Pagination ...
- Rstdio中更换R版本
1.打开Rstdio,选择Tool --> Global Options.
- Json.Net使用JSON Schema验证JSON格式
Json.NET supports the JSON Schema standard via the JsonSchema and JsonValidatingReader classes. It s ...
- iOS 进阶 第十七天(0420)
0420 凡是继承了UIResponder的类都可以做响应者 响应事件的传递是由底到高来传递,响应者链条是由高到底来响应 相应事件的传递(由底到高 找到正在和用户触摸交互的view) 准则:事件由父控 ...
- [转]log4net 使用指南
声明:本文内容主要译自Nauman Leghari的Using log4net,亦加入了个人的一点心得(节3.1.4). 请在这里下载示例代码 1 简介 1.1 ...
- [SSH服务]——SSH详解、常用的远程连接工具
在总结ssh原理前,我先做了一个ssh过程的实验 首先我搭建了这样一个实验环境: (1) SSH Server:10.0.10.198 (2) SSH Client:10.0.10.158 在Serv ...
- linux查看端口是否已开启和查看文件数
查看端口是否开启 lsof -i:80 查看文件数 ls | wc -w
- iframe 传值问题
当一个页面中插入了iframe或者由不同的框架组成(fieldset)时,这种情况下,需要处理的业务逻辑比较常见的就是数据进行交互了 1.页面中插入了iframe情况 由于页面中插入了iframe,那 ...