• 【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;
    }
    
  • 相关阅读:
    给博客园编辑器完善个插件及简单产品化工作
    在Visual Studio中新增生成项目
    用了三星Dex,我已经快一个月回家没开过电脑了
    BizTalk证书相关操作
    定长文本格式编辑神器
    B2B相关编码说明
    OFTP简介
    Apigee 简介与简单试用
    重置BizTalk RosettaNet
    BizTalk Map 累积连接字符串
  • 原文地址:https://www.cnblogs.com/tavee/p/16208340.html
Copyright © 2020-2023  润新知