您的位置:首页 > 其它

贪心算法之最小生成树Kruskal

2012-11-07 16:48 357 查看
求最小生成树有两种算法prim和kruskal。 前者适合于稠密图,它是根据节点到周围节点的最短路径来求的的。前面已经介绍过,本人也认为它编程思想比较简单适合于初学者。而kruskal根据边数来求的的,它始终取当前最小边加入,所以它适合于稀疏图,当边数非常多时,它就会很复杂。

很多数据结构书上都讲过这种贪心思想,这种思想还好理解,但是要将它具体写成程序还是有一些难度的,我想按照prim算法的思想,将最小边的节点放在visited[]数组中,如果最小边的节点访问过,则visited[i] = 1;否则为0.但是这种想法不行,比如下面第四幅图 ,1 ,3连接,2,6连接起来后,然后进行贪心的话,就会出现错误。



先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n
棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
#include <iostream>
#include <queue>
using namespace std;

priority_queue<struct Edge> pq;
// 并查集
class UFSet
{
int n;
int *root;

public:
~UFSet();
UFSet(int n);
int Find(int x);
void Merge(int x, int y);
};
class UFSet *ufset;

//函数定义
UFSet::UFSet(int n)
{
this->n = n;
root = new int[n+1];

for (int i = 1; i <= n; i++)
root[i] = i;
}

UFSet::~UFSet()
{
delete[] root;
}

int UFSet::Find(int x)
{
int t, r = root[x];
while (root[r] != r) r = root[r];     //这段其实也很不好理解,但可以结合上图的最后一幅图,假设其中1和4还有一条连线 ,就可以帮助我们理解了
/*hile (root[x] != r) // 路径压缩    //其实这段代码没有功能 ,个人看法。如果有不同的看法可以跟我说
{
t = root[x];
root[x] = r;
x = t;
}*/
return r;
}

void UFSet::Merge(int x, int y)
{
//int fx = Find(x);             //网上原先还是对形参进行find操作,但我觉得和main函数中的find重复操作,冗余,所以就将其伪码修改了下
//int fy = Find(y);
//if (fx != fy)
root[x] = y;
}

// 边
struct Edge
{
int left;
int right;
double dis;
bool operator < (const Edge& e) const
{
return dis > e.dis;
}
};
/* bool com(const Edge& e1,const Edge &e2)
{
return e1.dis < e2.dis;
}*/

// 边集合

double Kruskal()
{
double ans = 0;

while( ! pq.empty() )
{
struct Edge e = pq.top();
pq.pop();
int fx = ufset->Find(e.left);
int fy = ufset->Find(e.right);
if (fx != fy)
{
ufset->Merge(fx, fy);
ans += e.dis;
}
}

return ans;
}
int main()
{
cout<<"输入定点个数 :";
int v;
cin>>v;
UFSet uf(v);
ufset = &uf;
//ufset->UFSet(v);
struct Edge edge[100];
int n;
cout<<"输入边的个数:";
cin>>n;

for(int i=1; i<=n; i++)
{
cin>>edge[i].left>>edge[i].right;
cin>>edge[i].dis;
}

for(int i=1; i<=n; i++)
pq.push(edge[i]);

cout<<Kruskal()<<endl;
return 1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: