最小生成树的简单例题

来源:互联网 发布:星目读屏软件 编辑:程序博客网 时间:2024/06/05 02:04

**

灌溉(最小生成树)

**

到了旱季农业生产的灌溉就成了一个大问题。为了保证灌溉的顺利,某县政府决定投资为各个村之间建立灌溉管道。

输入第1行包括一个整数N,表示某县的村庄的数量。(3≤N≤100),第2行-结尾为一个N×N的矩阵,表示每个村庄之间的距离。虽然在理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为不会有线路从第i个村到它本身(任何两个村之间的距离都不大于100000)。

输出只有一个,为修建灌溉管道将所有村庄相连在一个灌溉系统里所需的最小管道长度。

样例输入

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
样例输出

28

第一种方法:Kruskal算法(用并查集做)

#include<iostream>#include<memory.h>#include<algorithm>#include<stdio.h>using namespace std;const int INF=99999;int per[20000];bool tag[20000];struct Edge{    int u;    int v;    int w;};Edge E[20000];int Find(int x){    int r=x;    while(r!=per[r])    {        r=per[r];        //找x的最终根节点    }    int i=x,j;    while(per[i]!=r)   //把x->到根节点过程中的直接或所有间接根节点的根节点,                      {                   //都改为以r为直接根节点        j=per[i];        per[i]=r;        i=j;    }    return r;}void join(int a,int b){    int Fx=Find(a),Fy=Find(b);    if(Fx!=Fy)    {        per[Fy]=Fx;    }}bool compare(Edge a,Edge b){    return a.w<b.w?true:false;}int main(){    int n;    scanf("%d",&n);    for(int i=0;i<n;i++)    {        per[i]=i;    }    int cost,k=0;    for(int i=0;i<n;i++)    {        for(int j=0;j<n;j++)        {            scanf("%d",&cost);            E[k].u=i;            E[k].v=j;            E[k].w=cost;            k++;        }    }    sort(E,E+k,compare);    int e_number=0,min_cost=0;    for(int i=0;i<k;i++)    {        if(Find(E[i].u)!=Find(E[i].v))//新找到的最小边的两个节点,        {                            //如果根不同,连接他们不会有回路            join(E[i].u,E[i].v);            e_number++;            min_cost+=E[i].w;        }        if(e_number==n-1)        {            break;        }    }    printf("%d\n",min_cost);    return 0;}

第二种方法:Prim算法(不断更新lowcost数组)

#include<stdio.h>#include<iostream>#include<algorithm>using namespace std;const int INF=999999;const int MAX=105;const int MAX2=10005;int path[MAX][MAX];int tag[MAX2];int lowcost[MAX2];int main(){    int n;    int min_cost=0,minn;  //min_cost:最小边权值和 minn:最小边的权值    scanf("%d",&n);    for(int i=0;i<n;i++)    {        for(int j=0;j<n;j++)        {            scanf("%d",&path[i][j]);        }    }    for(int i=0;i<n;i++)    {      lowcost[i]=path[0][i];    }    tag[0]=1;    for(int i=0;i<n-1;i++) //这一层循环的i只是代表,共执行n-1次。    {        minn=INF;        int next;        for(int j=0;j<n;j++)        {            if(tag[j]==0&&minn>lowcost[j])//每次i循环找出一条最小边            {                minn=lowcost[j];                next=j;            }        }        tag[next]=1;        min_cost+=minn;        for(int j=0;j<n;j++) //不断更新lowcost数组,以便下次i循环选择下条边        {            if(tag[j]==0&&(lowcost[j]>path[next][j]))            {                lowcost[j]=path[next][j];            }        }    }    printf("%d\n",min_cost);    return 0;}