题意:求解最小生成树的权值是否唯一,即要我们求次小生成树的权值
两种方法求最小生成树,一种用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(次小生成树)的更多相关文章

  1. POJ 1679 The Unique MST (次小生成树)

    题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...

  2. POJ 1679 The Unique MST (次小生成树 判断最小生成树是否唯一)

    题目链接 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. De ...

  3. POJ 1679 The Unique MST (次小生成树kruskal算法)

    The Unique MST 时间限制: 10 Sec  内存限制: 128 MB提交: 25  解决: 10[提交][状态][讨论版] 题目描述 Given a connected undirect ...

  4. poj 1679 The Unique MST (次小生成树(sec_mst)【kruskal】)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 35999   Accepted: 13145 ...

  5. poj 1679 The Unique MST 【次小生成树】【模板】

    题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...

  6. POJ 1679 The Unique MST 【最小生成树/次小生成树模板】

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22668   Accepted: 8038 D ...

  7. POJ1679 The Unique MST —— 次小生成树

    题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total S ...

  8. poj 1679 The Unique MST

    题目连接 http://poj.org/problem?id=1679 The Unique MST Description Given a connected undirected graph, t ...

  9. poj 1679 The Unique MST(唯一的最小生成树)

    http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submis ...

  10. poj 1679 The Unique MST (判定最小生成树是否唯一)

    题目链接:http://poj.org/problem?id=1679 The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total S ...

随机推荐

  1. Linux源代码情景分析读书笔记 物理页面的分配

    函数 alloc_pages流程图

  2. spring 3 的 @value的使用

    Spring 3支持@value注解的方式获取properties文件中的配置值,大大简化了我们读取配置文件的代码.使用方式如下: 1.首先必须要配置properties文件的加载bean:在spri ...

  3. hdu 2822 Dogs

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2822 Dogs Description Prairie dog comes again! Someda ...

  4. centos6 自启动任务

    tag: init upstart centos6.x 自启动 initctl event CentOS6开始转用Upstart代替以往的init.d/rcX.d的线性启动方式.upstart的概念就 ...

  5. python小算法(一)

    1.长度为m的字符串a,长度为n的字符串b,(m>n) 判断b中的字母是否全在a中? O(n)最小. class Num(object): def getNum(self, m): numLis ...

  6. 基于jquery的页面代码的优化

    高亮显示,选中的文字链接 显示效果如下 默认选择“通知公告”效果 通知公告 学院动态 行业动态       选择“学院动态”效果 通知公告 学院动态 行业动态       选择“行业动态”效果 通知公 ...

  7. 低噪声APD偏置电路

    低噪声APD偏置电路 APD电源摘要:该电路产生并控制光通信中雪崩光电二极管(APD)的低噪声偏置电压.该可变电压通过控制APD的雪崩增益,优化光纤接收器的灵敏度特性.该电路采用低噪声.固定频率PWM ...

  8. online training

    https://www.skillfeed.com/browse http://teamtreehouse.com/features http://www.pluralsight.com/ https ...

  9. html转义函数

    public static String filter(String message) { if (message == null) return (null); char content[] = n ...

  10. 用telnet和php的curl库测试http

    一.telnet测试http telnet简介     Telnet协议是TCP/IP协议族的其中之一,是Internet远端登录服务的标准协议和主要方式,常用于网页服务器的远端控制,可供使用者在本地 ...