并查集
A - 并查集
题目大意
现在有一个并查集,让你完成合并和查询操作
思路
并查集模板题
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int p[N];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m;
cin >> n >> m;
for(int i = 1;i <= n;i ++){
p[i] = i;
}
while(m --){
int z, a, b;
cin >> z >> a >> b;
if(z == 1){
if(find(a) == find(b)) continue;
else p[find(a)] = find(b);
}else{
if(find(a) == find(b)) cout << "Y" << endl;
else cout << "N" << endl;
}
}
return 0;
}
B - 修复公路
题目大意
给出 A 地区的村庄数 NN,和公路数 MM,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)。
思路
将每条道路的时间从小到大排序,每次合并道路的时候,都遍历一遍看一看是不是所有的道路都合并了,是的话直接输出此时的时间。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
struct node{
int x, y, t;
}d[N];
bool cmp(node b, node c){
return b.t < c.t;
}
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m;
cin >> n >> m;
for(int i = 1;i <= n;i ++){
p[i] = i;
}
for(int i = 0;i < m;i ++){
cin >> d[i].x >> d[i].y >> d[i].t;
}
sort(d, d + m, cmp);
for(int i = 0;i < m;i ++){
p[find(d[i].x)] = find(d[i].y);
int flag = 1;
for(int j = 1;j < n;j ++){
if(find(j) != find(j + 1)){
flag = 0;
}
}
if(flag){
cout << d[i].t;
return 0;
}
}
cout << -1;
return 0;
}
C - 亲戚
题目大意
给出一堆亲戚关系,看任意两人是不是亲戚关系
思路
并查集模板题
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10;
int p[N];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m, q;
cin >> n >> m >> q;
for(int i = 1;i <= n;i ++){
p[i] = i;
}
while(m --){
int a, b;
cin >> a >> b;
if(find(a) != find(b)) p[find(a)] = find(b);
}
while(q --){
int a, b;
cin >> a >> b;
if(find(a) == find(b)) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
D - 一中校运会之百米跑
题目大意
给你一堆名字,然后等一会问你他们是不是在同一组。
思路
并查集模板题
AC思路
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10;
unordered_map<string,int> q;
int p[N];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m;
cin >> n >> m;
for(int i = 1;i <= n;i ++){
string s;
cin >> s;
q[s] = i;
p[q[s]] = i;
}
while(m --){
string s1, s2;
cin >> s1 >> s2;
p[find(q[s1])] = find(q[s2]);
}
int k;
cin >> k;
while(k --){
string s1, s2;
cin >> s1 >> s2;
if(find(q[s1]) == find(q[s2])) cout << "Yes." << endl;
else cout << "No." << endl;
}
return 0;
}
E - 朋友
题目大意
A 公司有 N 名员工,其中有 P 对朋友关系。B 公司有 M 名员工,其中有 Q 对朋友关系。朋友的朋友一定还是朋友。小明和小红是朋友关系,小明的编号是1,小红的编号是-1,通过小明和小红的这层关系看看最多能凑成多少对情侣。
思路
主要是看看通过小明,a公司有多少人可以和b公司搭上关系,再看看通过小红,b公司有多少人可以和a公司搭上关系,取最小值即可。
AC思路
#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int> p;
unordered_map<int,int> w;
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m, t ,q;
cin >> n >> m >> t >> q;
for(int i = 1;i <= n;i ++){
p[i] = i;
}
for(int i = -1;i >= -m;i --){
p[i] = i;
}
while(t --){
int x, y;
cin >> x >> y;
if(find(x) != find(y)) p[find(x)] = find(y);
}
while(q --){
int x, y;
cin >> x >> y;
if(p[find(x)] != find(y)) p[find(x)] = find(y);
}
p[find(1)] = find(-1);
int ans = 0;
int cnt = 0;
for(int i = 1;i <= n;i ++){
if(find(i) == find(-1)){
ans ++;
}
}
for(int j = -1;j >= -m;j --){
if(find(j) == find(1)){
cnt ++;
}
}
cout << min(ans, cnt);
return 0;
}
F - 家谱
题目大意
给定一堆字符串,前面是‘#’则表明是父亲,前面是‘+’则表明是儿子,前面是‘?’则是询问这个人的祖宗是谁。
思路
并查集模板题,唯一可能要注意的点就是用一下map而已。
AC代码
#include<bits/stdc++.h>
using namespace std;
string s;
map<string,string> p;
string father;
string find(string x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin >> s && s != "$"){
if(s[0] == '#'){
father = s.substr(1);
if(p[father] == "") p[father] = father;
}
else if(s[0] == '+'){
string x = s.substr(1);
p[x] = find(father);
}else{
string x = s.substr(1);
cout << x << " " << find(x) << "\n";
}
}
return 0;
}