Head of a Gang 1446 并查集

来源:互联网 发布:南风知我意七微好看吗 编辑:程序博客网 时间:2024/05/17 02:07

按照自己的理解写了一遍代码,发现是不对的。

然后参考了之后,发现得用并查集。

我的也思考了我错误的代码,如果是


应当使用并查集搜索:对于这种情况就会出错
aaa bbb 13
ccc ddd 14
aaa ddd 15
会导致ccc 和其他三个人的集合标记不一致 


这种情况,就会导致集合标记不一致。

后来看了整个并查集的推导过程,很受启发。

最终版本的weight_qucik_union并查集有三个特点:

1、以寻找根节点的形式,标记一类结点;

2、为了使构造的树结构层数低,让size小的并到size大的树上;

3、为了进一步缩小树的层数,在find方法中,寻找爷爷结点,压缩树形。

参考了这篇文章,讲得很仔细,很不错:

http://blog.csdn.net/dm_vincent/article/details/7655764

树形结构层数降低的好处是,可以加快搜索,减少搜索的层数。


下面的代码,尽管没有ac,但是我觉得已经可以达到训练算法思想的目的了。应该某个细节我还没有考虑到。

/*1、录入数据。结构体。     1.1每个人为一类,随字母小的归为同一个编号     1.2求出每个人的通话时间   2、对每一类,看是否满足条件。 人数,通话时间。3、对满足的,求出head,以及人数number。存入结构体 4、按字典顺序输出   应当使用并查集搜索:对于这种情况就会出错aaa bbb 13ccc ddd 14aaa ddd 15会导致ccc 和其他三个人的集合标记不一致 */#include <stdio.h>#include <stdlib.h>typedef struct{char head[4];int number;}Gang;Gang result[27];int peo[27];//分类int peo_times[27];//每个人的通话时间 int count_union;//记录集合的个数 int size[27];//记录每个集合的大小--> 以决定两棵树结合的方向 int flag[27];//记录结点处理情况 //int max_head[27];//记录每个集合最大的gang即head int cmp(const void* p, const void* q){return (*(Gang *)p).head[0] - (*(Gang *)q).head[0];}int find(int p)//寻找根结点 {while( peo[p] != p){peo[p] = peo[peo[p]];//指向p结点的爷爷结点,压缩搜索 p = peo[p];}return p;}void unions(int p,int q)//连接两个结点 {int ra = find(p);int rb = find(q);if( ra == rb) return;//根结点一致,就不连接if( size[ra] < size[rb]) {peo[ra] = peo[rb];size[rb] += size[ra];}else  {peo[rb] = peo[ra];size[ra] += size[rb];}//count_union--;}int main(){int n,threth,times;int i,j,k;char a[4],b[4];while( scanf("%d%d", &n ,&threth) != EOF){for(i=0 ; i< 27 ;i++){peo[i] = i;peo_times[i] = 0;size[i] = 1;//每个集合的大小为1 //max_head[i]= -1;//result[i].number = -1;flag[i] = -1;}//count_union = 26;//1 读入数据,进行连接处理 for(i=0 ; i< n; i++){scanf("%s%s%d", a, b, ×);unions(a[0] - 'A',b[0] - 'A');peo_times[a[0]-'A'] += times;peo_times[b[0]-'A'] += times;}//搜索满足条件的gangint root;int rsu_count=0;int sum=0;for(i=0 ; i< 27 ; i++){root = find(i);int maxhead=-1;int max_index;//if(flag[root] == -1 && size[root] <= 2)//count_union--;if(flag[root] == -1 && size[root] > 2)//如果人数大于2,且没有访问过 {for(j=0 ; j< 27 ; j++)//寻找所有集合里面最大的gang {if( find(j) == root && peo_times[j] > maxhead){maxhead = peo_times[j];max_index = j;}}for(k=0 ; k<3 ; k++)//存入head和number result[rsu_count].head[k] = 'A'+max_index;result[rsu_count].head[k] = '\0';result[rsu_count++].number = size[max_index];flag[root] = 1;}}/*int rsu_count=0;for(i=0 ; i< n-1; ){//i 是开始索引 int sum=0,max=-1,max_index;for(j=i+1 ;j<n && peo[j]==peo[j-1]; j++);if(j-i >2)//如果人数大于两个人 {for(k=i ; k<j; k++)sum += peo_times[k];if( sum/2 > threth)//如果大于下限{for(k=i; k<j ; k++)if( peo_times[k] > max) {max = peo_times[k];max_index = k;}for(k=0 ; k<3 ; k++)//存入head和number result[rsu_count].head[k] = 'A'+max_index;result[rsu_count].head[k] = '\0';result[rsu_count++].number = j-i;} }i = j;} *///outputqsort(result, rsu_count, sizeof(Gang), cmp);printf("%d\n", rsu_count);for(i=0 ; i< rsu_count ; i++)printf("%s %d\n", result[i].head, result[i].number);}return 0;}


虽然在实习,但是代码的训练还是不能停呀。

话说原来看论文的消耗量,比我做工程的消耗量还要大的。

可能是做的工程比较顺手把~嘿嘿


0 0