zoukankan      html  css  js  c++  java
  • CF95E Lucky Country 题解

    Desciption

    CF95E Lucky Country

    Solution

    非常巧妙的 \(dp\) 题,sto xy学长 orz

    同一个区域的岛屿明显只能在一起,所以用并查集合并一下同一区域内的岛屿。

    然后我们要找出用最少的边连出一个幸运地区。

    那这不就是一个背包吗!

    朴素的状态:\(dp_{i, j}\) 表示考虑到前 \(i\) 个区域,一共有 \(j\) 个岛屿的最小连边数。

    朴素的转移方程:

    \[dp_{i, j} = \min\{dp_{i - 1, j - a_i} + 1\} \]

    \(a_i\):表示区域 \(i\) 中的岛屿个数。

    显然会 T,考虑优化。

    经典的二进制拆分就登场了,所以我们二进制拆一下跑个 01背包 即可。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    namespace IO{
        inline int read(){
            int x = 0;
            char ch = getchar();
            while(!isdigit(ch)) ch = getchar();
            while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
            return x;
        }
    
        template <typename T> inline void write(T x){
            if(x < 0) putchar('-'), x = -x;
            if(x > 9) write(x / 10);
            putchar(x % 10 + '0');
        }
    }
    using namespace IO;
    
    const int N = 1e5 + 10;
    int n, m, tot, cnt;
    int f[N], siz[N];
    int a[N], dp[N], w[N], v[N];
    
    inline int find(int x){
        return f[x] == x ? x : f[x] = find(f[x]);
    }
    
    inline void prework(){
        for(int i = 1; i <= n; ++i){
            if(!a[i]) continue;
            int tmp = 1;
            while(a[i]){
                w[++cnt] = i * tmp, v[cnt] = tmp;
                a[i] -= tmp, tmp <<= 1;
                if(a[i] < tmp && a[i]){
                    w[++cnt] = i * a[i], v[cnt] = a[i];
                    break;
                }
            }
        }
    }
    
    inline bool check(int x){
        while(x){
            if(x % 10 != 4 && x % 10 != 7) return 0;
            x /= 10;
        }
        return 1;
    }
    
    int main(){
        n = read(), m = read();
        for(int i = 1; i <= n; ++i) f[i] = i, siz[i] = 1;
        for(int i = 1; i <= m; ++i){
            int fu = find(read()), fv = find(read());
            if(fu != fv){
                if(siz[fu] < siz[fv]) swap(fu, fv);
                f[fu] = fv, siz[fv] += siz[fu];
            }
        }
        for(int i = 1; i <= n; ++i)
            if(find(i) == i) a[siz[i]]++;
        memset(f, 0x3f, sizeof(f));
        prework();
        f[0] = 0;
        for(int i = 1; i <= cnt; ++i)
            for(int j = n; j >= w[i]; --j)
                f[j] = min(f[j], f[j - w[i]] + v[i]);
        int ans = 1e9;
        for(int i = 1; i <= n; ++i)
            if(check(i)) ans = min(ans, f[i]);
        write(ans > n ? -1 : ans - 1);
        puts("");
        return 0;
    }
    

    \[\_EOF\_ \]

  • 相关阅读:
    【C语言】学习笔记9——结构struct(2)
    WPF dev 获取gridControl筛选后的数据
    WPF DEV dxc:ChartControl 柱状图
    WPF 重写ListBox(透明效果)
    WPF 后台重写 DataTemplate
    WPF 去掉Drag a column header here to group by that column
    c# 对DataTable进行分组group by
    c# ref与out用法
    WPF canvas设置旋转角度和偏移位置
    WPF 流加载
  • 原文地址:https://www.cnblogs.com/xixike/p/15738312.html
Copyright © 2011-2022 走看看