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

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使用GZIP压缩反回数据问题

《SpringBoot使用GZIP压缩反回数据问题》:本文主要介绍SpringBoot使用GZIP压缩反回数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot使用GZIP压缩反回数据1、初识gzip2、gzip是什么,可以干什么?3、Spr

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

一文详解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,或者在别人的电脑上,想