并查集题目(路径压缩、扩展域并查集、带权并查集、二维转一维并查集、逆向思维并查集)

2024-09-04 05:32

本文主要是介绍并查集题目(路径压缩、扩展域并查集、带权并查集、二维转一维并查集、逆向思维并查集),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

P2814 家谱

P1955 [NOI2015] 程序自动分析

P2256 一中校运会之百米跑    (并查集结合map)

P3144 [USACO16OPEN]Closing the Farm S

P6121 [USACO16OPEN]Closing the Farm G

P1197 [JSOI2008] 星球大战

P5092 [USACO04OPEN]Cube Stacking (带权并查集)

P5877 棋盘游戏

 P8686 [蓝桥杯 2019 省 A] 修改数组

P1840 Color the Axis

Supermarket

P2949 [USACO09OPEN]Work Scheduling G

P3402 可持久化并查集

P2814 家谱

#include <bits/stdc++.h>
using namespace std;
int len, cnt, father, fa[50010];
string s;
map<string, int> m;
string a[50010];
int find(int x)
{if(fa[x]==x){return x;}else return fa[x]=find(fa[x]);
}
int main()
{while(cin>>s && s[0]!='$'){string name="";len=s.length();for(int i=1; i<len; ++i){name+=s[i];}if(s[0]=='#'){if(m.count(name)!=0){father=m[name];continue;}cnt++;m[name]=cnt;a[cnt]=name;fa[cnt]=cnt;father=cnt;}else if(s[0]=='+'){if(m.count(name)!=0){int id=m[name];fa[id]=father;continue;}cnt++;m[name]=cnt;a[cnt]=name;fa[cnt]=father;}else if(s[0]=='?'){int id=m[name];cout << name << " " << a[find(id)] << endl;}}return 0;
}

P1955 [NOI2015] 程序自动分析

并查集和map(哈希)结合起来的一道好题

#include <bits/stdc++.h>
using namespace std;
int t, n, fa[1000010], cnt;
bool flag;
map<int, int> m;
struct node
{int x, y, z;
}limit[1000010];
bool cmp(node a, node b)
{return a.z>b.z;
}
int find(int x)
{if(fa[x]==x){return x;}return fa[x]=find(fa[x]);
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);if(fu!=fv){fa[fu]=fv;}
}
int main()
{scanf("%d", &t);while(t--){		//10scanf("%d", &n);m.clear();flag=true;for(int i=1; i<=n; ++i){		//1e6scanf("%d %d %d", &limit[i].x, &limit[i].y, &limit[i].z);}sort(limit+1, limit+n+1, cmp);	//1e6*20 for(int i=1; i<=n; ++i){		//1e6 int u=limit[i].x;int v=limit[i].y;int e=limit[i].z;if(m.count(u)==0){cnt++;fa[cnt]=cnt;	//初始化并查集	m[u]=cnt;		//将大范围的整数u映射成小范围的整数cnt }if(m.count(v)==0){cnt++;fa[cnt]=cnt;	//初始化并查集m[v]=cnt;		//将大范围的整数v映射成小范围的整数cnt }if(e==1){			//合并 merge(m[u], m[v]);} else{				//判断u和v的祖先是否相同 int fu=find(m[u]);int fv=find(m[v]);if(fu==fv){flag=false;printf("NO\n");break;}}}if(flag){printf("YES\n");	}}return 0;
}

P2256 一中校运会之百米跑    (并查集结合map)

#include <bits/stdc++.h>
using namespace std;
const int N=20010; 
int n, m, k, fa[N], u, v, fu, fv;
string name1, name2;
map<string, int> asd;
int find(int x)
{if(fa[x]==x){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=n; ++i){fa[i]=i;cin >> name1;asd[name1]=i;}while(m--){cin >> name1 >> name2;u=asd[name1];v=asd[name2];merge(u, v);}scanf("%d", &k);while(k--){cin >> name1 >> name2;u=asd[name1];v=asd[name2];if(find(u)==find(v)){printf("Yes.\n");}else{printf("No.\n");}}return 0;
}

P3144 [USACO16OPEN]Closing the Farm S

并查集倒着做合并, AC

#include <bits/stdc++.h>
using namespace std;
int n, m, u, v, close[3010], fa[3010], cnt;
bool in[3010], vis[3010];
string ans[3010];
vector<int> a[3010];
int find(int x)
{if(x==fa[x]){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);while(m--){scanf("%d %d", &u, &v);a[u].push_back(v);a[v].push_back(u);}for(int i=1; i<=n; ++i){fa[i]=i;scanf("%d", &close[i]);	//要关掉的谷仓编号 }for(int i=n; i>=1; --i){u=close[i];in[u]=true;		//该点加入到图中for(int j=0; j<a[u].size(); ++j){v=a[u][j];if(in[v]){merge(u, v);	}} memset(vis, 0, sizeof(vis));cnt=0;for(int j=1; j<=n; ++j){if(in[j] && !vis[find(j)]){vis[find(j)]=true;cnt++;if(cnt>1){break;}}}if(cnt>1){ans[i]="NO";}else{ans[i]="YES";}}for(int i=1; i<=n; ++i){cout << ans[i] << endl;}return 0;
}

暴力做法,50分, TLE

#include <bits/stdc++.h>
using namespace std;
int n, m, a[3010][3010], u, v, start[3010], close, vis[3010], cnt;
queue<int> q;
bool check(int x)
{//多测清空 cnt=0;memset(vis, 0, sizeof(vis));while(!q.empty()){q.pop();}//找起点 for(int i=1; i<=n; ++i){if(start[i]==false){q.push(i);vis[i]=true;cnt=1;break;		}}//遍历 while(!q.empty()){if(cnt==n-x){return true;}u=q.front();q.pop();for(int i=1; i<=n; ++i){if(a[u][i] && !vis[i]){vis[i]=true;cnt++;q.push(i);}}}return false;
}
int main()
{scanf("%d %d", &n, &m);while(m--){scanf("%d %d", &u, &v);a[u][v]=a[v][u]=1;	//建边 }for(int i=1; i<=n; ++i){if(check(i-1)){		//关掉i-1个谷仓	printf("YES\n");}else{printf("NO\n");}scanf("%d", &close);	//要关掉的谷仓编号 start[close]=true;		//标记为关闭状态 for(int j=1; j<=n; ++j){	//断边 a[close][j]=a[j][close]=0;	}}return 0;
}

P6121 [USACO16OPEN]Closing the Farm G

#include <bits/stdc++.h>
using namespace std;
int n, m, u, v, close[200010], fa[200010], cntedge, cntnode;
bool in[200010], vis[200010];
string ans[200010];
vector<int> a[200010];
int find(int x)
{if(x==fa[x]){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);while(m--){scanf("%d %d", &u, &v);a[u].push_back(v);a[v].push_back(u);}for(int i=1; i<=n; ++i){fa[i]=i;scanf("%d", &close[i]);	//要关掉的谷仓编号 }//O(M)for(int i=n; i>=1; --i){u=close[i];cntnode++;in[u]=true;		//该点加入到图中for(int j=0; j<a[u].size(); ++j){v=a[u][j];if(in[v] && find(u)!=find(v)){merge(u, v);	cntedge++;}} if(cntedge+1<cntnode){ans[i]="NO";}else{ans[i]="YES";}}for(int i=1; i<=n; ++i){cout << ans[i] << endl;}return 0;
}

P1197 [JSOI2008] 星球大战

#include <bits/stdc++.h>
using namespace std;
int n, m, u, v, k, close[400010], fa[400010], cntedge, cntnode, asd;
int ans[400010];
bool in[400010], vis[400010];
vector<int> a[400010];
int find(int x)
{if(x==fa[x]){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);for(int i=0; i<n; ++i){fa[i]=i;}while(m--){scanf("%d %d", &u, &v);a[u].push_back(v);a[v].push_back(u);}scanf("%d", &k); for(int i=1; i<=k; ++i){scanf("%d", &close[i]);	//要关掉的星球编号vis[close[i]]=true;		//如果某个星球始终没有被关掉, 则vis为false }asd=n-k;	//假设这些点都没相连, 联通块数量最多为n-k //逆向思维处理, 反向建设相当于正向摧毁 //先处理k座星球全部被摧毁后的情况 for(int i=0; i<n; ++i){if(!vis[i]){	//i始终没有被摧毁 in[i]=true;	//i在图里 for(int j=0; j<a[i].size(); ++j){	v=a[i][j];	//枚举与i相连的点 if(!vis[v] && find(i)!=find(v)){	//如果该点也始终没有被摧毁, 并且有边相连 merge(i, v);	//合并 asd--;		//联通块数量减一 }}}}ans[k+1]=asd;//再逆向处理第i座星球被摧毁前的情况for(int i=k; i>=1; --i){//把第i座星球加入到图中 u=close[i];asd++;in[u]=true;		//该点加入到图中for(int j=0; j<a[u].size(); ++j){v=a[u][j];if(in[v] && find(u)!=find(v)){	//连一条边, 没有形成环 merge(u, v);	//合并 asd--;			//联通块数量-- }} ans[i]=asd;}for(int i=1; i<=k+1; ++i){cout << ans[i] << endl;}return 0;
}

P5092 [USACO04OPEN]Cube Stacking (带权并查集)

#include <bits/stdc++.h>
using namespace std;
const int N=30010;
int p, fa[N], dis[N], size[N], u, v;
char opt; 
int find(int x)
{if(fa[x]==x){return x;}int root=find(fa[x]);		//找到自己祖宗结点的祖宗 dis[x]+=dis[fa[x]];			//更新到自己祖宗的祖宗(root)的距离, 等于自己到当前祖宗结点的距离+当前祖宗结点到它的祖宗结点的距离 return fa[x]=root;			//直接链到最终的祖宗 
}
void merge(int u, int v)
{int fu, fv; fu=find(u);fv=find(v);if(fu==fv)	return;fa[fu]=fv;dis[fu]+=size[fv];		//距离先存在祖宗结点fu这里, 后面需要用的时候find去更新 size[fv]+=size[fu];		//祖宗保存元素个数 
} 
int main()
{scanf("%d", &p);for(int i=1; i<=N; ++i){	//并查集初始化, dis[i]默认为0 fa[i]=i;	size[i]=1;}while(p--){cin >> opt;if(opt=='M'){			//将包含 u 的立方柱移动到包含 v 的立方柱上scanf("%d %d", &u, &v);		merge(u, v); }else if(opt=='C'){		//统计含 u 的立方柱中,在 u 下方的方块数目。scanf("%d", &u);find(u);printf("%d\n", dis[u]);}}return 0;
}

P5877 棋盘游戏

二维转一维,用并查集处理

#include <bits/stdc++.h>
using namespace std;
int n, m, c, x, y, a[510][510], fa[250010], id, asd;
int mx[5]={0, -1, 1, 0, 0};
int my[5]={0, 0, 0, -1, 1};
int find(int x)
{if(fa[x]==x){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=n; ++i){for(int j=1; j<=n; ++j){id=(i-1)*n+j;fa[id]=id;}}memset(a, -1, sizeof(a));while(m--){scanf("%d %d %d", &c, &x, &y);asd++;id=(x-1)*n+y;a[x][y]=c;for(int i=1; i<=4; ++i){int nx=x+mx[i];int ny=y+my[i];if(nx>=1 && nx<=n && ny>=1 && ny<=n && a[nx][ny]==c && find(id)!=find((nx-1)*n+ny)){merge(id, (nx-1)*n+ny);asd--;}}printf("%d\n", asd);}return 0;
}

 P8686 [蓝桥杯 2019 省 A] 修改数组

路径压缩,删除中间的数,相当于区间合并

#include <bits/stdc++.h>
using namespace std;
int n, fa[2000010], a[100010];
bool vis[2000010];
int find(int x)
{if(fa[x]==x){return x;}	else{return fa[x]=find(fa[x]);}
} 
void merge(int u, int v)
{int fu=find(u);int fv=find(v);fa[fu]=fv;
}
int main()
{scanf("%d", &n);for(int i=1; i<=2000000; ++i){fa[i]=i;}for(int i=1; i<=n; ++i){scanf("%d", &a[i]);}for(int i=1; i<=n; ++i){if(find(a[i])==a[i]){		//没出现 cout << a[i] << " ";merge(a[i], a[i]+1);}else{	//出现过 cout << fa[a[i]] << " ";merge(fa[a[i]], fa[a[i]]+1);}}return 0;
}

P1840 Color the Axis

并查集进行区间合并

#include <bits/stdc++.h>
using namespace std;
int n, m, fa[200010], l, r, asd;
int find(int x)
{if(x==fa[x]){return x;}else{return fa[x]=find(fa[x]);}
}
void merge(int u, int v)
{int fu=find(u);int fv=find(v);//让大的当父亲, 不然会TLE fa[fu]=fv;
}
int main()
{scanf("%d %d", &n, &m);asd=n;//注意细节, 需要初始化到n+1, 不然TLE for(int i=1; i<=n+1; ++i){fa[i]=i;}	while(m--){scanf("%d %d", &l, &r);for(int i=l; i<=r; i=find(i)){//如果该点没有被涂过 if(find(i)==i){		asd--;		//答案-- //该点被涂过了, 将该点和下一个点合并,//当下次再找到该点时, 直接通过find(i)跳到下一个没有被涂的点 merge(i, i+1);		 }	}printf("%d\n", asd);	}return 0;
}

Supermarket

Supermarket - 洛谷

P2835 刻录光盘

P1333 瑞瑞的木棍

P2391 白雪皑皑

P2949 [USACO09OPEN]Work Scheduling G

P3402 可持久化并查集

这篇关于并查集题目(路径压缩、扩展域并查集、带权并查集、二维转一维并查集、逆向思维并查集)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1135131

相关文章

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个

Java常用注解扩展对比举例详解

《Java常用注解扩展对比举例详解》:本文主要介绍Java常用注解扩展对比的相关资料,提供了丰富的代码示例,并总结了最佳实践建议,帮助开发者更好地理解和应用这些注解,需要的朋友可以参考下... 目录一、@Controller 与 @RestController 对比二、使用 @Data 与 不使用 @Dat

Linux修改pip和conda缓存路径的几种方法

《Linux修改pip和conda缓存路径的几种方法》在Python生态中,pip和conda是两种常见的软件包管理工具,它们在安装、更新和卸载软件包时都会使用缓存来提高效率,适当地修改它们的缓存路径... 目录一、pip 和 conda 的缓存机制1. pip 的缓存机制默认缓存路径2. conda 的缓

Spring组件初始化扩展点BeanPostProcessor的作用详解

《Spring组件初始化扩展点BeanPostProcessor的作用详解》本文通过实战案例和常见应用场景详细介绍了BeanPostProcessor的使用,并强调了其在Spring扩展中的重要性,感... 目录一、概述二、BeanPostProcessor的作用三、核心方法解析1、postProcessB

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

Python中Windows和macOS文件路径格式不一致的解决方法

《Python中Windows和macOS文件路径格式不一致的解决方法》在Python中,Windows和macOS的文件路径字符串格式不一致主要体现在路径分隔符上,这种差异可能导致跨平台代码在处理文... 目录方法 1:使用 os.path 模块方法 2:使用 pathlib 模块(推荐)方法 3:统一使

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

CSS3 最强二维布局系统之Grid 网格布局

《CSS3最强二维布局系统之Grid网格布局》CS3的Grid网格布局是目前最强的二维布局系统,可以同时对列和行进行处理,将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,本文介... 深入学习 css3 目前最强大的布局系统 Grid 网格布局Grid 网格布局的基本认识Grid 网

MySQL9.0默认路径安装下重置root密码

《MySQL9.0默认路径安装下重置root密码》本文主要介绍了MySQL9.0默认路径安装下重置root密码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录问题描述环境描述解决方法正常模式下修改密码报错原因问题描述mysqlChina编程采用默认安装路径,