51nod 1212——无向图最小生成树

无向图最小生成树


N个点M条边的无向连通图,每条边有一个权值,求该图的最小生成树。


Input 第1行:2个数N,M中间用空格分隔,N为点的数量,M为边的数量。(2 <= N <= 1000, 1 <= M <= 50000)
第2 - M + 1行:每行3个数S E W,分别表示M条边的2个顶点及权值。(1 <= S, E <= N,1 <= W <= 10000) Output 输出最小生成树的所有边的权值之和。 Sample Input
9 14
1 2 4
2 3 8
3 4 7
4 5 9
5 6 10
6 7 2
7 8 1
8 9 7
2 8 11
3 9 2
7 9 6
3 6 4
4 6 14
1 8 8
Sample Output
37

解题思路:

        其实就是一道最小生成树的模板题,用Kruskal算法来写。将每条路的信息存储起来,并将边的权值按从小到大进行排序,每次选择权值最小的边加入树中,并把边的两个顶点加入到一个集合中,若这两个顶点本身就在一个集合中(即加入这条边就构成了回路),就舍弃这条边判断下一个。直到选取了n-1条边加入树中,最小生成树构造完成。具体看代码。


代码如下:

    

#include
#include
#include
#define INF 0x3f3f3f3f  //定义极大值INF
using namespace std;

int n, m, sum, ans;
int f[1010];     //数组f判断点的集合状态

struct node
{
    int x;
    int y;       //存储边的两个顶点以及权值
    int z;
} Q[50010];

bool cmp( node a, node b )
{
    return a.z < b.z;  //将权值从小到大排列
}

int getf( int v )
{
    if( v != f[v] )
        f[v] = getf(f[v]);  //查找父节点
    return f[v];
}

int lian( int t1, int t2 )
{
    int v1 = getf(t1);
    int v2 = getf(t2);
    if( v1 != v2 )
    {                  //若两个顶点不在同一集合中,这条边加入树
        f[v1] = v2;
        return 1;
    }
    return 0;
}

void Kruskal()
{
    for( int i = 0; i < m; i++ )
    {
        if( lian(Q[i].x,Q[i].y) )
        {
            ans++;
            sum = sum + Q[i].z;
            if( ans == n-1 ) //当选取n-1条边时最小生成树构造完成
                break;
        }
    }
}

int main()
{
    while( ~scanf("%d%d",&n,&m) )
    {
        for( int i = 0; i < m; i++ )
            scanf("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].z);
        sort(Q,Q+m,cmp);
        sum = ans = 0;
        for( int i = 1; i <= n; i++ )
            f[i] = i; //初始化父节点都是本身
        Kruskal();
        printf("%d\n",sum);
    }
    return 0;
}

你可能感兴趣的:(*****最小生成树*****)