Topic 4: parallel search unit (dsu)

Posted by will on Sat, 01 Jan 2022 19:08:27 +0100

other

1.HDU 1272 Xiao Xi's maze

  • This question is old. Pro test:
    (1) There is a set of test samples. Only two zeros are entered for additional judgment.
    (2) The number is not necessarily 1~n, and there is a number jump.
    (3) See the problem clearly. Make sure the graph is connected.
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = 100005;
int par[maxn], ranking[maxn];
int N;

void init(int n);
int find(int x);
void unite(int x, int y);
bool same(int x, int y);

int main()
{
    int u, v;
    while(scanf("%d%d", &u, &v) && (u != -1) && (v != -1)){
        if(u == 0 && v == 0){
            printf("Yes\n");
            continue;
        }
        vector<int> vs;
        vs.push_back(u);
        vs.push_back(v);

        bool flag = 1;
        init(maxn);
        unite(u, v);

        while(scanf("%d%d", &u, &v) && u){
            if(same(u, v)){
                flag = 0;
            }
            unite(u, v);
            vs.push_back(u);
            vs.push_back(v);
        }
        int sz = vs.size();
        for(int i = 0; i < vs.size(); i++){
            if(!same(vs[0], vs[i])){
                flag = 0;
            }
        }
        if(flag){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }
    }
    return 0;
}
void init(int n)
{
    for(int i = 1; i <= n; i++){
        par[i] = i;
        ranking[i] = 0;
    }
}
int find(int x)
{
    if(par[x] == x){
        return x;
    }
    return par[x] = find(par[x]);
}
void unite(int x, int y)
{
    x = find(x);
    y = find(y);
    if(x == y){
        return;
    }
    if(ranking[x] < ranking[y]){
        par[x] = y;
    }
    else{
        par[y] = x;
        if(ranking[x] == ranking[y]){
            ranking[x]++;
        }
    }
}
bool same(int x, int y)
{
    return find(x) == find(y);
}

2.240. Food chain

This question shows the practice of snow food. It's a little hard to understand anyway. I can't. listen again.

#include<cstdio>
const int maxn = 50005;
int p[maxn], d[maxn];
int N, K;
void init(int N) {
	for (int i = 1; i <= N; i++) p[i] = i;
}
int find(int x) {
	if (p[x] == x) return x;
	else {
		int u = find(p[x]);
		d[x] += d[p[x]];
		return p[x] = u;
	}
}
int main() {
	scanf("%d%d", &N, &K);
	init(N);
	int res = 0;
	while (K--) {
		int t, a, b;
		scanf("%d%d%d", &t, &a, &b);
		int pa = find(a), pb = find(b);
		if (a > N || b > N) {
			res++;
			continue;
		}
		if (t == 1) {
			//pa == pb means that the two have established a relationship.
			if (pa == pb && (d[a] - d[b]) % 3)  res++;
			//The else if condition can be entered only if the two have not established a connection, otherwise the previous condition cannot be changed.
			else if(pa != pb){
				p[pa] = pb;
				d[pa] = d[b] - d[a];
				//Here is the sum d [a] + X - D [b]% 3 = = 0, X is d[pa], and it will be solved.
			}
		}
		else {
			if (pa == pb && (d[a] - d[b] - 1) % 3) res++;
			else if(pa != pb){
				p[pa] = pb;
				d[pa] = d[b] - d[a] + 1;
			}
		}
	}
	printf("%d\n", res);
}

3.Eliminate danger

It was the lab teacher who asked me to pack the chemicals. If any n chemicals in the box contain exactly n elements, it will form an explosive mixture.

This question can be regarded as whether to form a ring. If a ring is formed, it will explode. Each edge between two objects is equivalent to one more substance. If a ring is formed, the number of points and the number of edges are equal, and it explodes.

#include<cstdio>
#include<set>
using namespace std;
const int maxn = 100010;
int p[maxn];
void init(int N) {
	for (int i = 1; i <= N; i++) {
		p[i] = i;
	}
}
int find(int x) {
	if (p[x] == x) return x;
	return p[x] = find(p[x]);
}
int unite(int x, int y) {
	if (find(x) == find(y)) return 0;
	p[find(x)] = find(y);
	return 1;
}
int main() {
	init(100000);
	int a, b, cnt = 0, ans = 0;

	while (scanf("%d", &a) && a != -1) {
		scanf("%d", &b);
		if (!unite(a, b)) ans++;
	}
	printf("%d\n", ans);
	return 0;
}

4.1252. Matching purchase

  • And check the + 01 knapsack problem. It's not difficult.
  • One thing worth mentioning is to judge whether it is an ancestor node. If p[x] == x, then x is an ancestor node. Otherwise, it is not an ancestor node.
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int p[maxn], v[maxn], w[maxn], N, M, W, f[maxn];
void init(int N) {
	for (int i = 1; i <= N; i++) p[i] = i;
}
int find(int x) {
	if (p[x] == x) return x;
	return p[x] = find(p[x]);
}
void unite(int a, int b) {
	if (find(a) == find(b)) return;
	v[find(b)] += v[find(a)];
	w[find(b)] += w[find(a)];
	p[find(a)] = find(b);
}
int main() {
	scanf("%d%d%d", &N, &M, &W);
	init(N);
	for (int i = 1; i <= N; i++) {
		scanf("%d%d", &w[i], &v[i]);
	}
	while (M--) {
		int a, b;
		scanf("%d%d", &a, &b);
		unite(a, b);
	}
	for (int i = 1; i <= N; i++) {
		if (p[i] != i) continue;
		for (int j = W; j >= w[i]; j--) {
			f[j] = max(f[j], f[j - w[i]] + v[i]);
		}
	}
	printf("%d\n", f[W]);
	return 0;
}

cf

1.B1. Books Exchange (easy version)

This topic is about passing books between students. Ask how many days you can come back.

In the parallel search set, the idea of this ring is too important. This is, but just look at the size of the formed ring, that is, how many days it takes to come back.

#include<cstdio>
int p[200005], sz[200005], a[200005];
void init(int N) {
	for (int i = 1; i <= N; i++) {
		p[i] = i;
		sz[i] = 1;
	}
}
int find(int x) {
	if (p[x] == x) return x;
	return p[x] = find(p[x]);
}
void unite(int x, int y) {
	if (find(x) == find(y)) return;
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int N;
		scanf("%d", &N);
		init(N);
		for (int i = 1; i <= N; i++) {
			scanf("%d", &a[i]);
		}
		for (int i = 1; i <= N; i++) {
			unite(i, a[i]);
		}
		for (int i = 1; i <= N; i++) {
			printf("%d%c", sz[find(i)], i == N ? '\n' : ' ');
		}
	}
	return 0;
}

2.B. Drazil and His Happy Friends

This question is so easy to make mistakes! This question is about N boys and M girls. Then on the i day, the i% N boy can date the i% m girl, and then as long as one of them is happy, they all become happy.

This problem can be so abstract. Attach an attribute to the elements of the same collection. Only one element among them has this attribute, so add it to the collection. The unite function is shown here. Be sure to pay attention to the position where the attribute is changed. Be sure to change before judging whether they are the same set.

void unite(int x, int y) {
	if (happy[x] || happy[y]) happy[find(y)] = 1;
	if (find(x) == find(y)) return;
	p[find(x)] = find(y);
}

However, this problem can be solved as a thinking problem. Because we found that whether they can meet or not is related to the maximum common divisor of N and m. For example, when n is 2 and M is 4, some people can't meet. Therefore, only when g is the greatest common divisor, all satisfied x, as long as one person is happy, then all x will be happy.

Therefore, we can let x traverse from 0 to g - 1. Then see if there is happy in N and M. If there is no one, output No. Specifically:

#include<cstdio>
#include<algorithm>
using namespace std;
int b[105], g[105];
int gcd(int a, int b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
int main() {
	int N, M, A, B, tmp;
	scanf("%d%d", &N, &M);
	scanf("%d", &A);
	for (int i = 0; i < A; i++) {
		scanf("%d", &tmp);
		b[tmp] = 1;
	}
	scanf("%d", &B);
	for (int i = 0; i < B; i++) {
		scanf("%d", &tmp);
		g[tmp] = 1;
	}
	int G = gcd(N, M);
	int flag = true;
	for (int x = 0; x < G; x++) {
		int ok = false;
		for (int i = x; i < N; i += G) {
			if (b[i]) {
				ok = true;
				break;
			}
		}
		for (int i = x; i < M; i += G) {
			if (g[i]) {
				ok = true;
				break;
			}
		}
		if (!ok) {
			flag = false;
			break;
		}
	}
	if (flag) printf("Yes\n");
	else printf("No\n");
	return 0;
}

Topics: Algorithm