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 ...
随机推荐
- wpf的datepicker处理
如果有2个datepicker,控制时间起和止的话,可以把第二个datepicker加一个属性,DisplayDateStart = "{Binding SelectedDate,Eleme ...
- Linux 配置 vimrc
由于熟悉了Windows下利用编译器进行编程,所以在刚刚接触Linux后的编程过程中会感觉其vim编译器的各种不方便编写程序,在逐渐的学习过程中了解到可以通过配置vimrc使得vim编译时类似于VS. ...
- jdbc 连接 oracle rac
jdbc 连接 oracle rac 的连接串如下: jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 192. ...
- ORACLE-用户常用数据字典的查询使用方法
一.用户 查看当前用户的缺省表空间 SQL> select username,default_tablespace from user_users; USERNAME DEFAULT_TABLE ...
- iOS学习之C语言函数
一.函数的定义 返回值类型 函数名(参数类型 参数名, ...) { 功能语句; return 返回值; } 按照返回值和参数划分: 第一种: 无返回值 无参 void sayHello() { pr ...
- 用Swift重写公司OC项目(Day2)--创建OC与Swift的桥接文件,进而调用OC类库
昨天把项目中的图标以及启动转场图片弄好了,那么今天,我们可以开始慢慢进入到程序的编写当中了. 由于swift较新,所以类库还不够完善,但是不用担心,苹果早就出了解决方案,那就是使用桥接文件,通过桥接文 ...
- [转]ubuntu 10.04下的配置tftp服务器
[转]ubuntu 10.04下的配置tftp服务器 http://www.cnblogs.com/geneil/archive/2011/11/24/2261653.html 第1步:安装tftp所 ...
- 28.USB的传输类型
USB上必须将数据组织成 事务 才能够进行传输.事务常有两个或三个包.令牌包用于启动一个事务,由主机发送:数据包传送数据,方向由令牌包确定:握手包常是数据接收方发送的,用于表示接收数据的状态.USB协 ...
- Python实现C4.5(信息增益率)
Python实现C4.5(信息增益率) 运行环境 Pyhton3 treePlotter模块(画图所需,不画图可不必) matplotlib(如果使用上面的模块必须) 计算过程 st=>star ...
- ArrayList、LinkedList、Vector的区别
Arraylist和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以插入数据慢,查找有下标, ...