王道机试5.2 并查集 含练习

王道机试5.2 并查集 含练习

例5.1 畅通工程

#include<stdio.h>
using namespace std;
int tree[1000];
 
int findroot(int x)
{
    if(tree[x]==-1)
        return x;
    else
    {
        int ret=findroot(tree[x]);
        tree[x]=ret;
        return ret;
    }
 }
  
 int main()
 {
    int m,n;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        scanf("%d",&m);
        for(int i=1;i<=n;i++)
            tree[i]=-1;
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            int ra=findroot(a);
            int rb=findroot(b);
            if(ra!=rb)
                tree[ra]=rb;
         }
         int ans=0;
         for(int i=0;i<=n;i++)
         {
            if(tree[i]==-1)
                ans++;
         }
         printf("%d\n",ans-1);
     }
    return 0;
 }

练1:连通图

#include<stdio.h>
using namespace std;
int tree[1000]; 

int findroot(int x)
{
	if(tree[x]==-1)
		return x;
	else
	{
		int ret=findroot(tree[x]);
		tree[x]=ret;
		return ret;
	}
 } 
 
 int main()
 {
 	int m,n;
 	while(scanf("%d%d",&n,&m)!=EOF)
 	{
 		if(m==0&&n==0)
 			break;
 		for(int i=1;i<=n;i++)
 			tree[i]=-1;
 		for(int i=0;i<m;i++)
 		{
 			int a,b;
 			scanf("%d%d",&a,&b);
			int ra=findroot(a);
			int rb=findroot(b);
			if(ra!=rb)
				tree[ra]=rb;
		 }
		 int ans=0;
		 for(int i=0;i<=n;i++)
		 {
		 	if(tree[i]==-1)
		 		ans++;
		 }
		if(ans>1)
		 	printf("NO\n");
		else
			printf("YES\n");
		 
	 }
	return 0;
 }

练3:Head of a Gang
使用并查集。
建立了两个结构体,一个person用于保存每个人的名字、权重、所在集合的根节点下标。一个gang用于保存结果,每个帮派的头目及帮派的成员。之所以需要第二个结果结构体是因为我在并查集的过程中无法保证根节点为头目,输出时没办法按名字升序输出,所以用一个结果结构体数组sort一下再输入。在建立一个sum数组保存每个集合的总权重,用于与k比较。
牛客网代码来源
https://www.nowcoder.com/questionTerminal/a31b1ea6c87647bc86e382acaf21c53b?f=discussion

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 26
using namespace std;
typedef struct Person{
    char name[5];
    int weight;
    int parents;//parents保存集合的根节点下标,根节点的parent保存集合成员个数
}Person;
typedef struct gang{
    char head[5];
    int number;
}gang;//结果结构体保存头目和帮派人数
Person p[N];
int sum[N];
bool cmp(gang a,gang b){
    return strcmp(a.head,b.head)<0;
}//字典排序函数
int FindRoot(int x){
    if(p[x].parents<0) return x;//parents小于0代表是根节点,且数值为成员个数
    else{
        p[x].parents=FindRoot(p[x].parents);
        return p[x].parents;
    }
}//并查集函数
int main(){
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF){
        getchar();//用于消除缓冲区回车防止字符串输入出错
        int i;
        for(i=0;i<N;i++){
            p[i].parents=-1;
            p[i].weight=0;
            sum[i]=0;
        }//初始化
        while(n--){
            char name1[5],name2[5];
            int weight,no1,no2,p1,p2;
            scanf("%s%s%d",name1,name2,&weight);
            getchar();//用于消除缓冲区同上
            no1=name1[0]-'A';
            no2=name2[0]-'A';//由名字找到这个人下标
            strcpy(p[no1].name,name1);//记得要保存该人的名字
            p[no1].weight+=weight;//每遇到这个人就要加上一次权重
            strcpy(p[no2].name,name2);
            p[no2].weight+=weight;
            p1=FindRoot(no1);
            p2=FindRoot(no2);
            if(p1!=p2){//不是同一个集合要合并
                p[p1].parents+=p[p2].parents;
                p[p2].parents=p1;
                sum[p1]=sum[p1]+sum[p2]+weight;
            }//合并的过程,顺便加上集合的总权重
            else
                sum[p1]+=weight;//如果是同一个集合也要加上权重
        }
        int ans=0;//保存帮派数目
        gang g[10];//结果数组,26个人帮派最多有8个,10的数组够了
        for(i=0;i<N;i++){
            if(p[i].parents<-2&&sum[i]>k){//人数超过2人,总权重大于k则为帮派
                g[ans].number=-p[i].parents;//保存下帮派人数
                int parent=i;//根节点存一下,其实有点多余,可以直接用i
                int max=i;//权重最大者下标,初始为根节点
                for(int j=0;j<N;j++){
                    if(FindRoot(j)==parent&&p[j].weight>p[max].weight)
                        max=j;//如果属于此集合且权重更大,替换一下
                }
                strcpy(g[ans].head,p[max].name);//把头目名字存进来
                ans++;//接着存下一个帮派
            }
        }
        printf("%d\n",ans);//输入帮派数目
        sort(g,g+ans,cmp);//按字典sort一下
        for(i=0;i<ans;i++)
            printf("%s %d\n",g[i].head,g[i].number);//输出头目名字和帮派人数
    }
    return 0;//over,哈哈
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值