算法提高课第四章并查集

并查集有两个功能:合并集合、查询祖宗节点
优化方式:路径压缩,按秩合并
记录每个集合的大小,绑定到根节点。记录每个点到根节点的距离,绑定到子节点
并查集的高级应用:扩展并查集、带权并查集

1250. 格子游戏 - AcWing题库

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 40010;
int n, m;
int f[N];
int a[N];
int get(int x, int y)
{
    return x * n + y;
}
int find(int x)
{
    if(f[x] == x) return x;
    return f[x] = find(f[x]);
}
int main()
{
    cin >> n >> m;
    for(int i = 0; i < n * n; i ++ ) f[i] = i;
    
    int res = 0;
    for(int i = 1; i <= m; i ++ )
    {
        int x, y;
        char t;
        cin >> x >> y >> t;
        x --, y --;
        int a = get(x, y);
        int b;
        if(t == 'D') b = get(x + 1, y);
        else b = get(x, y + 1);
        
        a = find(a), b = find(b);
        if(a == b)
        {
            res = i;
            break;
        }
        f[a] = b;
    }
    if(res) cout << res;
    else cout << "draw";
}

1252. 搭配购买 - AcWing题库

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 10010;
int f[N];
int n, m, V;
int v[N], w[N];
int dp[N];
int find(int x)
{
    if(f[x] == x) return x;
    return f[x] = find(f[x]);
}
int main()
{
    cin >> n >> m >> V;
    for(int i = 1; i <= n; i ++ ) f[i] = i;
    for(int i = 1; i <= n; i ++ )
        cin >> v[i] >> w[i];
    for(int i = 1; i <= m; i ++ )
    {
        int a, b;
        cin >> a >> b;
        a = find(a);
        b = find(b);
        if(a != b)
        {
            f[a] = b;
            w[b] += w[a];
            v[b] += v[a];
        }
    }
    for(int i = 1; i <= n; i ++ )
    if(f[i] == i)
    for(int j = V; j >= v[i]; j -- )
    {
        dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
    }
    cout << dp[V];
}

237. 程序自动分析 - AcWing题库

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 100000;
int f[2 * N + 100];
int a1[N + 100], b1[N + 100], c1[N + 100];
int find(int x)
{
    if(f[x] == x) return x;
    return f[x] = find(f[x]);
}
int main()
{
    int t; cin >> t;
    while(t -- )
    {
        vector<int> g1, g2;
        int n; cin >> n;
        for(int i = 1; i <= 2 * N; i ++ ) f[i] = i;
        int flag = true;
        int cnt = 0;
        unordered_map<int, int> mp;
        for(int i = 1; i <= n; i ++ )
        {
            cin >> a1[i] >> b1[i] >> c1[i];   
            if(c1[i]) g1.push_back(i);
            else g2.push_back(i);
            if(!mp[a1[i]])//没有a[i];
            mp[a1[i]] = ++ cnt;
            
            if(!mp[b1[i]])//没有b[i];
            mp[b1[i]] = ++ cnt;
        }
        for(int i = 0; i < g1.size(); i ++ )
        {
            int a = mp[a1[g1[i]]], b = mp[b1[g1[i]]];
            a = find(a);
            b = find(b);
            f[a] = b;
        }
        for(int i = 0; i < g2.size(); i ++ )
        {
            int a = mp[a1[g2[i]]], b = mp[b1[g2[i]]];
            a = find(a);
            b = find(b);
            if(a == b) flag = false;
        }
        if(flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
}

238. 银河英雄传说 - AcWing题库

//询问相隔多少战舰
//需要维护集合大小和到祖宗的距离 
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 30010;

int m;
int f[N], s[N], d[N];
int find(int x)
{
    if(f[x] == x) return x;
    int root = find(f[x]);
    d[x] += d[f[x]];
    return f[x] = root;
}
int main()
{
    cin >> m;
    for(int i = 1; i < N; i ++ )
    {
        f[i] = i;
        s[i] = 1;
    }
    for(int i = 1; i <= m; i ++ )
    {
        char t;
        int a, b;
        cin >> t >> a >> b;
        if(t == 'M')
        {
            a = find(a);
            b = find(b);
            d[a] = s[b];
            s[b] += s[a];
            f[a] = b;
            
        }
        else
        {
            int fa = find(a);
            int fb = find(b);
            //不能把a、b变成他的祖宗
            if(fa != fb) puts("-1");
            else printf("%d\n", max(0, abs(d[a] - d[b]) - 1));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值