201812-4 数据中心
时间限制:1.0s
内存限制:512MB
题目描述:
分析
我们可以发现,Tmax的最小值就是图的最小生成树的最大边,因此可以选择Prim算法或者Kruskal算法。而Kruskal算法会对边进行排序,更便于我们找到最大边,因此选择Kruskal算法。步骤如下:
- 对边进行排序
- 加入边时判断是否构成环(并查集)
解法
首先选择数据结构存储输入数据,输入数据主要是边的信息,数据结构如下:
struct Edge
{
unsigned int u, v;
long t;
bool operator < (const Edge& a)const
{
return t < a.t;
}
}e[MAXM];
Edge e[MAXM];//用数组存储边
接着定义并查集存储图的连通性:
//并查集初始化,每个节点的父节点都是自己
void init(unsigned int n)
{
unsigned int i;
for (i = 0; i < n; i++)
{
f[i] = i;
}
}
//查找根节点并返回,途中进行路径压缩
unsigned int find(unsigned int i)
{
unsigned int tmp = i;
while (f[tmp] != tmp)//找到根节点为tmp
{
tmp = f[tmp];
}
while (i != tmp)//从i到根节点的路上,每个结点都让其指向根节点
{
unsigned int k = i;
i = f[i];
f[k] = tmp;
}
return tmp;
}
//合并两个集合,并且返回是否可以合并的判断
bool join(unsigned int a, unsigned int b)
{
unsigned int fa = find(a);
unsigned int fb = find(b);
if (fa != fb)
{
f[fb] = fa;//注意是根节点合并
return true;
}
return false;
}
Kruskal算法实现:
for (unsigned int i = 0; i < m; i++)
{
unsigned int a, b;
a = e[i].v;
b = e[i].u;
if (join(a, b))//如果可以合并则不会构成环
{
count++;
ans = e[i].t;
if (count == n - 1)//添加n-1条边后即构成最小生成树
break;
}
}