uva 11354 Bond
2013-12-14 20:03
295 查看
这题要求最小瓶颈路 , 由于数据太多 , 所以用一般的bfs或dfs肯定会超时 。
在这个题目上就应该充分的考虑到 , 最小生成树是一棵树 , 所有就可以通过树的性质来解决这个问题 。
1、首先把最小生成树 , 建成一颗有根树 , 最好用bfs因为dfs可能会爆栈。
2、在建树的时候 ,
记录每个点的深度(根节点的深度为0)、每个节点的父亲节点(根节点的为-1)、每个节点和父亲节点的距离(根节点为0);
3、然后再通过题目给出的两个节点 , 来遍历这颗树 。
4、如果这两个节点的深度不一样 , 那么就先要把深度调成一样 ,
5、深度一样之后 , 再同时往树根的方向遍历 , 则在这个遍历过程 , 一定会得到两个节点的祖先是一样的 ,
到了这个时候就得到了我们想要的结果。
时间复杂度分析:这个算法之所以快 , 是因为我们两个节点同时在走 , 就等于是双向搜索一样 , 并且大多数情况下 ,
都不需要遍历所有的节点。
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct node
{
int from ,
to ;
int
dist;
node(int
from , int to , double dist)
{
this->from = from;
this->to
= to;
this->dist = dist;
}
bool
operator <(const struct node &ans) const
{
return dist
> ans.dist;
}
}; // 这是为了用优先队列来存储所有边
const int MAXN = 50000+5 ;
int n , m , p[MAXN] , f[MAXN];
// 记录父亲节点 、 深度
int dist[MAXN]; //
记录节点和父亲节点的距离
priority_queueedge;
void init()
{
int i , x ,
y , z;
for(i = 1; i
<= n; i++)
f[i] =
i;
for(i = 1; i
<= m; i++)
{
scanf("%d %d
%d" , &x , &y , &z);
edge.push(node(x , y , z));
}
memset(dist
, 0 , sizeof(dist));
memset(p , 0
, sizeof(p));
}
int find(int x) //并查集 ,
来判断新加入的两个节点是否属于同一个连通图
{
int y =
x;
while(x !=
f[x])
x =
f[x];
while(y !=
x)
{
int xy =
f[y];
f[y] =
x;
y =xy;
}
return
x;
}
void mintree() // 求最小生成树 ,
并将其转变为有根树
{
int bz
=0 , done[MAXN];
vectords[MAXN];
vectorq[MAXN];
while(!edge.empty())
{
struct node
s = edge.top();
edge.pop();
int x =
find(s.from) , y = find(s.to);
if(x !=
y)
{
f[y] =
x;
bz +=
1;
q[s.from].push_back(s.to); //用邻接表来记录最小生成树的边 , 并记录所加入边的权 ,
并使其相对应
q[s.to].push_back(s.from);
ds[s.to].push_back(s.dist);
ds[s.from].push_back(s.dist);
}
if(bz ==
n-1) break;
在这个题目上就应该充分的考虑到 , 最小生成树是一棵树 , 所有就可以通过树的性质来解决这个问题 。
1、首先把最小生成树 , 建成一颗有根树 , 最好用bfs因为dfs可能会爆栈。
2、在建树的时候 ,
记录每个点的深度(根节点的深度为0)、每个节点的父亲节点(根节点的为-1)、每个节点和父亲节点的距离(根节点为0);
3、然后再通过题目给出的两个节点 , 来遍历这颗树 。
4、如果这两个节点的深度不一样 , 那么就先要把深度调成一样 ,
5、深度一样之后 , 再同时往树根的方向遍历 , 则在这个遍历过程 , 一定会得到两个节点的祖先是一样的 ,
到了这个时候就得到了我们想要的结果。
时间复杂度分析:这个算法之所以快 , 是因为我们两个节点同时在走 , 就等于是双向搜索一样 , 并且大多数情况下 ,
都不需要遍历所有的节点。
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct node
{
int from ,
to ;
int
dist;
node(int
from , int to , double dist)
{
this->from = from;
this->to
= to;
this->dist = dist;
}
bool
operator <(const struct node &ans) const
{
return dist
> ans.dist;
}
}; // 这是为了用优先队列来存储所有边
const int MAXN = 50000+5 ;
int n , m , p[MAXN] , f[MAXN];
// 记录父亲节点 、 深度
int dist[MAXN]; //
记录节点和父亲节点的距离
priority_queueedge;
void init()
{
int i , x ,
y , z;
for(i = 1; i
<= n; i++)
f[i] =
i;
for(i = 1; i
<= m; i++)
{
scanf("%d %d
%d" , &x , &y , &z);
edge.push(node(x , y , z));
}
memset(dist
, 0 , sizeof(dist));
memset(p , 0
, sizeof(p));
}
int find(int x) //并查集 ,
来判断新加入的两个节点是否属于同一个连通图
{
int y =
x;
while(x !=
f[x])
x =
f[x];
while(y !=
x)
{
int xy =
f[y];
f[y] =
x;
y =xy;
}
return
x;
}
void mintree() // 求最小生成树 ,
并将其转变为有根树
{
int bz
=0 , done[MAXN];
vectords[MAXN];
vectorq[MAXN];
while(!edge.empty())
{
struct node
s = edge.top();
edge.pop();
int x =
find(s.from) , y = find(s.to);
if(x !=
y)
{
f[y] =
x;
bz +=
1;
q[s.from].push_back(s.to); //用邻接表来记录最小生成树的边 , 并记录所加入边的权 ,
并使其相对应
q[s.to].push_back(s.from);
ds[s.to].push_back(s.dist);
ds[s.from].push_back(s.dist);
}
if(bz ==
n-1) break;
相关文章推荐
- 最小生成树的一些性质和理解
- poj 2485 简单的最小生…
- 我的博客今天0岁42天了,我领取了…
- LA 4080 Warfare A…
- hdu 2433 最短路树
- 【快速】排序, T(n) = O(nlgn),O(n^2) S(n) = O(lgn) --- 不稳定
- (C# 基础) 类访问修饰符
- LA 3713 Astronauts
- LA 3211 Now or later
- uva 11324
- LA 5135 Mining Your Own Business
- http://kb.cnblogs.com/page/130970/ -http协议
- poj 2942 LA3523 点-双…
- uva 10047
- STL中优先队列的用法
- 并查集及其路径的压缩
- 求欧拉回路的路径 dfs的一种新运用
- poj 2676
- poj 2531
- poj 2251