poj1679 The Unique MST(判定次小生成树)
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 23180 | Accepted: 8235 |
Description
Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties:
1. V' = V.
2. T is connected and acyclic.
Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all
the edges in E'.
Input
triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.
Output
Sample Input
- 2
- 3 3
- 1 2 1
- 2 3 2
- 3 1 3
- 4 4
- 1 2 2
- 2 3 2
- 3 4 2
- 4 1 2
Sample Output
- 3
- Not Unique!
Source
对于最小生成树(能够用kruskal和prime算法求得,在这里我是用kruskal求得,假设不会请自己百度。),边的权值的和最小称为最小生成树。
而次小生成树就是除了最小生成树外的最小生成树。并且全部的次小生成树都是通过最小生成树的换边得到的。
所以难点就是怎样换边。
对于怎样换边:
1.先求出最小生成树,值为x。
2.一一枚举加入不在生成树上的边(这时候一定形成了一个环)
3.寻找环上的(最小生成树上的边)权值最大值与你所加入不在生成树上的边的权值比較,所得到的差值为min。
因为是一一枚举加入边,min有多个,求出最小的哪一个,所以次小生成树就为x+min。
昨天尽管把这道题A了,但是看到讨论区的測试数据发现自己又一个没有过,然而却AC了。然后今天起床就来研究研究。
。
。
发现我的程序是在找最大值。但是假设一个环有分支,它还会去找分支里面的最大值。于是就又优化了一下。
用的优先队列。
先附上第一次做的代码:
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- using namespace std;
- struct node
- {
- int a,b,cost;
- }c[10005];
- int fa[105],tree[105][105],vis[10005],vis_tree[105];//vis数组是对m对数据的标记vis_tree是对最小生成树标记
- int n,m,max1;
- bool cmp(node x,node y)
- {
- if(x.cost<y.cost)
- return true;
- else
- return false;
- }
- int find(int x)//寻找根
- {
- if(fa[x]!=x) fa[x]=find(fa[x]);
- return fa[x];
- }
- void sec_tree(int a,int b)//查找生成树某条边的最大值(我在这里做的是错误的。假设形成的环有分支,也会查找)
- {
- vis_tree[a]=1;
- if(a==b)
- return ;
- for(int i=1;i<=n;i++)
- if(tree[a][i]&&!vis_tree[i])
- {
- if(max1<tree[a][i])
- max1=tree[a][i];
- sec_tree(i,b);
- }
- }
- int main()
- {
- int ncase;
- scanf("%d",&ncase);
- while(ncase--)
- {
- memset(vis,0,sizeof(vis));
- memset(tree,0,sizeof(tree));
- memset(&c,0,sizeof(&c));
- scanf("%d %d",&n,&m);
- for(int i=1;i<=n;i++)
- fa[i]=i;
- for(int i=0;i<m;i++)
- scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost);
- sort(c,c+m,cmp);
- int sum=0;
- for(int i=0;i<m;i++)//kruskal算法求最小生成树
- {
- int x=find(c[i].a);
- int y=find(c[i].b);
- if(x!=y)
- {
- fa[x]=y,sum+=c[i].cost;
- tree[x][y]=tree[y][x]=c[i].cost;
- vis[i]=1;
- }
- }
- int flag=0;
- for(int i=0;i<m;i++)
- {
- if(!vis[i])//不在生成树中的边和形成的环的最大值比較。假设相等,MST不唯一
- {
- max1=-1;
- memset(vis_tree,0,sizeof(vis_tree));
- sec_tree(c[i].a,c[i].b);
- if(max1==c[i].cost)
- {
- flag=1;
- break;
- }
- }
- }
- if(!flag)
- printf("%d\n",sum);
- else
- printf("Not Unique!\n");
- }
- }
这是优化后的代码。凝视和上面一样。就一个地方不同:
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- #include <queue>
- using namespace std;
- struct node1
- {
- int a,b,cost;
- friend bool operator<(node1 x,node1 y )
- {
- return x.cost<y.cost;
- }
- };
- priority_queue<node1>s;
- struct node
- {
- int a,b,cost;
- }c[10005];
- int fa[105],tree[105][105],vis[10005],vis_tree[105];
- int n,m,max1,flag1;
- bool cmp1(node x,node y)
- {
- if(x.cost<y.cost)
- return true;
- else
- return false;
- }
- int find(int x)
- {
- if(fa[x]!=x) fa[x]=find(fa[x]);
- return fa[x];
- }
- void sec_tree(int a,int b)
- {
- node1 temp;
- vis_tree[a]=1;
- if(a==b)//假设找到a=b,标记一下
- {
- flag1=1;
- }
- for(int i=1;i<=n;i++)
- if(tree[a][i]&&!vis_tree[i])
- {
- temp.a=a,temp.b=i,temp.cost=tree[a][i];
- s.push(temp);
- if(!flag1)//就是在这里和上面不同,假设找不到a=b,那么就把曾经的恢复
- s.pop(),vis_tree[i]=0,sec_tree(i,b);
- }
- }
- int main()
- {
- int ncase;
- scanf("%d",&ncase);
- while(ncase--)
- {
- memset(vis,0,sizeof(vis));
- memset(tree,0,sizeof(tree));
- memset(&c,0,sizeof(&c));
- scanf("%d %d",&n,&m);
- for(int i=1;i<=n;i++)
- fa[i]=i;
- for(int i=0;i<m;i++)
- scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].cost);
- sort(c,c+m,cmp1);
- int sum=0;
- for(int i=0;i<m;i++)
- {
- int x=find(c[i].a);
- int y=find(c[i].b);
- if(x!=y)
- {
- fa[x]=y,sum+=c[i].cost;
- tree[x][y]=tree[y][x]=c[i].cost;
- vis[i]=1;
- }
- }
- int flag=0;
- for(int i=0;i<m;i++)
- {
- if(!vis[i])
- {
- int flag1=0;
- while(!s.empty())
- s.pop();
- memset(vis_tree,0,sizeof(vis_tree));
- sec_tree(c[i].a,c[i].b);
- node1 temp;
- temp=s.top();
- if(temp.cost==c[i].cost)
- {
- flag=1;
- break;
- }
- }
- }
- if(!flag)
- printf("%d\n",sum);
- else
- printf("Not Unique!\n");
- }
- }
poj1679 The Unique MST(判定次小生成树)的更多相关文章
- POJ-1679 The Unique MST(次小生成树、判断最小生成树是否唯一)
http://poj.org/problem?id=1679 Description Given a connected undirected graph, tell if its minimum s ...
- POJ1679 The Unique MST 【次小生成树】
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20421 Accepted: 7183 D ...
- POJ1679 The Unique MST【次小生成树】
题意: 判断最小生成树是否唯一. 思路: 首先求出最小生成树,记录现在这个最小生成树上所有的边,然后通过取消其中一条边,找到这两点上其他的边形成一棵新的生成树,求其权值,通过枚举所有可能,通过这些权值 ...
- POJ1679 The Unique MST(次小生成树)
可以依次枚举MST上的各条边并删去再求最小生成树,如果结果和第一次求的一样,那就是最小生成树不唯一. 用prim算法,时间复杂度O(n^3). #include<cstdio> #incl ...
- The Unique MST(次小生成树)
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22335 Accepted: 7922 Description Give ...
- POJ1679The Unique MST(次小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25203 Accepted: 8995 D ...
- poj 1679 The Unique MST【次小生成树】
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24034 Accepted: 8535 D ...
- POJ 1679:The Unique MST(次小生成树&&Kruskal)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19941 Accepted: 6999 D ...
- poj 1679 The Unique MST 【次小生成树】【模板】
题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...
- POJ 1679 The Unique MST (次小生成树)题解
题意:构成MST是否唯一 思路: 问最小生成树是否唯一.我们可以先用Prim找到一棵最小生成树,然后保存好MST中任意两个点i到j的这条路径中的最大边的权值Max[i][j],如果我们能找到一条边满足 ...
随机推荐
- freeMark
1. 什么是freemark Freemaker是一个”模板引擎”,也可以说是一个基于模板技术的生成文本输出的一个通用工具 2.一般的用途: l 能用来生成任意格式的文本:HTML,XML ...
- C/C++(语句,数组)
C语言语句: 两大选择,三大循环,四大跳转 两大跳转:if,switch 三大循环:for,while,do-while 四大跳转:break,continue,goto,return do-whil ...
- cf1089d Distance Sum
题目大意 给一个有n个点,m条边的无向连通图,求所有点两两之间的最短路.$(2<=n<=10^5;n-1<=m<=n+42)$ solution 我们注意到$m-n+1$很小. ...
- last---显示用户最近登录信息
last命令用于显示用户最近登录信息.单独执行last命令,它会读取/var/log/wtmp的文件,并把该给文件的内容记录的登入系统的用户名单全部显示出来. 语法 last(选项)(参数) 选项 - ...
- 负载均衡之lvs
集群(cluster):将一组计算机软/硬件连接起来,高度紧密的协作完成计算工作,其中的单个计算机通常称为节点.负载均衡集群(Load Balancing):通过负载均衡器,将负载尽可能平均分摊处理. ...
- 【2017 Multi-University Training Contest - Team 3】RXD's date
[Link]: [Description] [Solution] [NumberOf WA] 1 [Reviw] [Code] #include <bits/stdc++.h> using ...
- iOS 基于第三方QQ授权登录
基于iOS实现APP的第三方QQ登陆.接入第三方SDK时的一个主要的步骤: 1,找到相关的开放平台.QQ互联平台,http://connect.qq.com/: 2,注冊成功后创建自己的APP.填写一 ...
- POJ--2516--Minimum Cost【最小费用最大流】
链接:http://poj.org/problem?id=2516 题意:有k种货物,n个客户对每种货物有一定需求量,有m个仓库.每一个仓库里有一定数量的k种货物.然后k个n*m的矩阵,告诉从各个仓库 ...
- 终结者:借助pinyin4j相关jar包提取汉字的首字母
import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCase ...
- 李笑来~执行力WWH
什么是秘密 秘密是指只有极少数人知道的实用信息.这个实用信息可以为知道且懂得运用的人获得收益,这个收益可能包括钱.名声和快感. 什么是执行力 执行力=What + Why + How,即WWH 执行力 ...