今天POJ的刷题排名终于过了10000名,虽然刷题数目还是没有过了百题,名次是动态的,如果半天不再过题的一定会被其他人挤出万名之外,所以在今后还要再接再厉,向着5000名次进发!
贴张图纪念一下下:
让我挤进前万名行列的是刚才刷的一道MST题,不过不是最小生成树(Minimal Spanning Tree)题,而是最大生成树(Maxmal Spanning Tree 不知道在数据结构上有没有这个专业名次)题,点击打开链接进入题目,通过这道题也让我察觉到了我对Kruskal算法存在一些错误的理解,之前认为KrusKal()如果返回正值则是权值,返回0则表示无向图不连通,其实不然,正确的理解是:如果无向图是连通的,则返回权值,如果不连通,则返回此无向图的的生成树的边数。
附上Kruskal算法:
struct edge{
int u, v, w;
};
const int NODE_NUM = 102;
edge e[NODE_NUM*NODE_NUM];
int father[NODE_NUM];
int n, ne; //n是顶点的个数,ne是边的个数
bool cmp(const edge& a, const edge& b)
{
return a.w < b.w;
}
void make_set()
{
for (int i = 1; i <= n; ++i)
father[i] = i;
}
int find_set(int i)
{
if (father[i] != i){
father[i] = find_set(father[i]);
}
return father[i];
}
bool union_set(int a, int b) //a --> b
{
a = find_set(a);
b = find_set(b);
if (a != b){ //没有共同祖先,说明没有形成回路
father[a] = b; //将节点纳入最小生成树集合
return true;
}
else{
return false;
}
}
int kruskal()
{
int i, mst_edge = 0, sum = 0;
make_set();
sort(e, e+ne, cmp); //将边按升序排序
for (i = 0; i < ne; ++i){
//如果加入的边不会使树形成回路
if (union_set(e[i].u, e[i].v)){
sum += e[i].w;
//如果纳入的边数等于顶点数-1,则说明最小生成树形成
if (++mst_edge == n - 1){
return sum; //如果图是连通图,返回权值
}
}
}
return mst_edge; //如果不是连通图,则返回最大的连通(可以是多个生成树)的边的个数,
//return -1; 表示无向图不连通;
}