1 条题解

  • 0
    @ 2026-9-25 1:46:09

    Problem

    求出能打开所有存钱罐的情况下,需要破坏的存钱罐的最少数量

    Solution

    这道题让你求出连通块的个数。而将一个存钱罐钥匙放在另一个存钱罐十分像并查集中的合并。所以这道题可以用并查集做。

    1:初始化并查集

    void Init () {
    	for (int i = 1; i < _maxNum + 1; i++) {
    		_father[i] = i;//每个人的初始父亲都是他自己
    	}
    }
    

    2:查找

    int Find (int x) {
    	while (_father[x] != x) {
    		x = _father[x] = Find(_father[x]);//递归,路径压缩
    	}
    	
    	return x;
    }
    

    3:合并

    void Merge (int one, int two) {
        _father[Find(one)] = Find(two);//将两个节点合并到一起
    }
    

    4:查找连通块

    for (int i = 1; i < _maxNum + 1; i++) {
    	if (_father[i] == i) {
    		_ans++;//如果找到了结果加一
    	}
    }
    

    然后,我们就可以愉快的AC了

    ACCode

    
    
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    
    using namespace std;
    
    int _maxNum;
    int _father[1000009];
    int _ans = 0;
    
    int Find (int x) {
    	while (_father[x] != x) {
    		x = _father[x] = Find(_father[x]);
    	}
    	
    	return x;
    }
    
    void Init () {
    	for (int i = 1; i < _maxNum + 1; i++) {
    		_father[i] = i;
    	}
    }
    
    void Merge (int one, int two) {
        _father[Find(one)] = Find(two);
    }
    
    void ParseIn () {
    	int curInt;
    	scanf("%d", &_maxNum);
    	Init();
    	
    	for (int i = 1; i < _maxNum + 1; i++) {
    		scanf("%d", &curInt);
    		Merge(curInt, i);
    	}
    }
    
    void Core () {
    	for (int i = 1; i < _maxNum + 1; i++) {
    		if (_father[i] == i) {
    			_ans++;
    		}
    	}
    }
    
    void CWriteOut () {
    	printf("%d\n", _ans);
    }
    
    int main () {
    
    	ParseIn();
    	Core();
    	CWriteOut();
    
    	return 0;
    }
    
    • 1

    信息

    ID
    3184
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    2
    已通过
    2
    上传者