【ACM程序设计】求最小生成树 Kuskual算法

Kuskual算法

流程

  • 1 将图G看做一个森林,每个顶点为一棵独立的树
  • 2 将所有的边加入集合S,即一开始S = E( 并查集)
  • 3 从S中拿出一条最短的边(u,v),如果(u,v)不在同一棵树内,则连接u,v合并这两棵树,同时将(u,v)加入生成树的边集E'
  • 重复(3)直到所有点属于同一棵树,边集E'就是一棵最小生成树

typedef struct
{
    int a,b;
    int w;
}Road;
Road road[maxSize];
//并查集 获取根节点
int getRoot(int i)
{
    if(fa[i]==i) return i; //递归出口,当到达了祖先位置,就返回祖先
    else 
    {
        fa[i]=getRoot(fa[i]); //路径压缩
        return fa[i]; //不断向上查找祖先
    }
}
//n是节点个数 m是边数
void Kruskal(Road road[],int n,int m,int &sum)
{
    int a,b;
    sum=0;
    for(int i=0;i<n;i++)
        v[i]=i;
    sort(road,m);
    for(int i=0;i<n;i++)
    {
        a=getRoot(road[i].a);
        b=getRoot(road[i].b);
        if(a!=b)
        {
            v[a]=b;
            sum+=road[i].w;
        }
    }
}

例题

P1194 买礼物 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

输入 #2

3 3
0 2 4
2 0 2
4 2 0

输出

7

说明/提示

样例解释 2。

先买第 2 样东西,花费 3 元,接下来因为优惠,买 1,3 样都只要 2 元,共 7 元。

(同时满足多个“优惠”的时候,聪明的明明当然不会选择用 4 元买剩下那件,而选择用 2 元。)

数据说明:1<=B<=500 A>=0 Ki j<=1000

#include <stdio.h>
#define MaxN 501

typedef struct {
	int need;
	int from, to;
} node;

int father[ MaxN ];
node mp[ 250001 ]; //点数的最大值是500 故可能有500*499条边

void Sort( int left, int right ) {
	if ( left > right ) {
		return;
	}
	int i, j;
	node k;
	i = left, j = right;
	k = mp[ left ];
	while ( i != j ) {
		while ( k.need >= mp[ j ].need && i != j ) {
			j --;
		}
		if ( i != j ) {
			mp[ i ++ ] = mp[ j ];
		}
		while ( k.need <= mp[ i ].need && i != j ) {
			i ++;
		}
		if ( i != j ) {
			mp[ j -- ] = mp[ i ];
		}
	}
	mp[ i ] = k;
	Sort( left, i - 1 );
	Sort( i + 1, right );
	return;
}

int Find( int i) {
	if(father[i]==i) return i; //递归出口,当到达了祖先位置,就返回祖先
    else 
    {
        father[i]=Find(father[i]); //路径压缩
        return father[i]; //不断向上查找祖先
    }
}

int main( ) {
	int i, j, k;
	int A, B;
	int posi = 1;
	int ans = 0, cnt = 1;
	scanf("%d %d", &A, &B );
	for ( i = 1; i <= B; i ++ ) {
		father[ i ] = i;
	}
    //设置节点结构体数组
	for ( i = 1; i <= B; i ++ ) {
		for ( j = 1; j <= B; j ++ ) {
			scanf("%d", &k );
            //只设置邻接矩阵左下角的边即可
			if ( i > j ) {
				mp[ posi ].from = i;
				mp[ posi ].to = j;
				if ( k ) {
					k = A - k;  // 如果k 不为零,那么就把k的数值变为A-k
				}
				mp[ posi ++ ].need = k;
			}
		}
	}
    //开始Kruskal算法
	Sort( 1, posi - 1 );
	for ( i = 1; cnt < B ; i ++ ) {
		if ( Find( mp[ i ].from ) != Find( mp[ i ].to ) ) {
			if ( mp[ i ].need < 0 ) {
				mp[ i ].need = 0;
			}
			father[ father[ mp[ i ].to ] ] = father[ mp[ i ].from ];
			ans += mp[ i ].need;
			cnt ++;
		}
	}
	ans = B * A - ans;
	printf("%d\n", ans );
	return 0;
}
posted @ 2022-04-29 21:21  tavee  阅读(46)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************