首页 > 其他分享 >RegenDay01

RegenDay01

时间:2024-02-07 17:46:59浏览次数:27  
标签:int auto self cin dfs RegenDay01 sum

基本情况

学到了不少,多谢雷根哥!

拼接1学了另外两种写法,拼接2学了正解,后面还学到用拓扑排序判环,以及dfs来找连通块中的点数量

充满希望的拼接质数1

T246207 充满希望的拼接质数1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

MySolution

DFS,通过让下标递增来找不同方案。

int main()
{
    int n;
    cin >> n;
    vector<int> a(n);
    for (auto& i : a) cin >> i;
    int ans = 0;
    auto check = [&](int x) {
        if (x < 2) return false;
        for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
        return true;
    };
    auto dfs = [&](auto self, int ind, int sum)->void {
        if (check(sum)) ans++;
        for (int i = ind + 1; i < n; i++) {
            self(self, i, sum + a[i]);
        }
    };
    dfs(dfs, -1, 0);
    cout << ans << endl;
    return 0;
}

\(\text{RegenSolution}\)

  • DFS选或不选

    int main()
    {
        int n;
        cin >> n;
        vector<int> a(n);
        for (auto& i : a) cin >> i;
        int ans = 0;
        auto check = [&](int x) {
            if (x < 2) return false;
            for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
            return true;
        };
        auto dfs = [&](auto self, int now, int sum)->void {
            if (now == n) {
                if (check(sum)) ans++;//这里要在now == n的时候才能计数,因为这个方法是选或不选,now = n时的方案才是一到n个物品中有的选有的不选的方案。
                return ;
            }
            self(self, now + 1, sum);//不选当前这个
            self(self, now + 1, sum + a[now]);//选当前这个
        };
        dfs(dfs, 0, 0);
        cout << ans << endl;
        return 0;
    }
    
  • 用二进制来枚举

    int main()
    {
        int n;
        cin >> n;
        vector<int> a(n);
        for (auto& i : a) cin >> i;
        int ans = 0;
        auto check = [&](int x) {
            if (x < 2) return false;
            for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
            return true;
        };
        
        for (int j = 0; j < (1 << n); j++) {//n位代表n个物品选或不选,从0到1<<n自然覆盖了所有情况
            int sum = 0;
            for (int i = 0; i < n; i++) {
                if (j & (1 << i)) sum += a[i];//拆位分析,如果该位选了,综合加上
            }
            if (check(sum)) ans++;
        }
    
        cout << ans << endl;
        return 0;
    }
    

充满希望的拼接质数2

T246208 充满希望的拼接质数2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

MySolution

这题验证方案不同的方式仅仅是数值不同,我用了两个方法都过不了。

  • 数组标记

    int main()
    {
        int n;
        cin >> n;
        vector<int> a(n);
        for (auto& i : a) cin >> i;
        sort(all(a));
        int ans = 0;
        auto check = [&](int x) {
            if (x < 2) return false;
            for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
            return true;
        };
        array<array<bool, 1001>, 13> vis;//第step步的数不能重复,(没啥逻辑的想法)
        auto dfs = [&](auto self, int ind, int sum, int step)->void {
            if (check(sum)) ans++;
            for (int i = ind + 1; i < n; i++) {
                if (!vis[step + 1][a[i]]) {
                    vis[step + 1][a[i]] = true;
                    self(self, i, sum + a[i], step + 1);
                }
            }
        };
        dfs(dfs, -1, 0, 0);
        cout << ans << endl;
        return 0;
    }
    
  • 暴力判断

    int main()
    {
        int n;
        cin >> n;
        vector<int> a(n);
        for (auto& i : a) cin >> i;
        sort(all(a));
        int ans = 0;
        auto check = [&](int x) {
            if (x < 2) return false;
            for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
            return true;
        };
        vector<vector<int> > total_res;//暴力存下所有结果,然后一个个比
        auto dfs = [&](auto self, int ind, int sum, vector<int>& res)->void {
            if (check(sum)) {
                bool ok = true;
                for (auto vec : total_res) {
                    if (vec.size() != res.size()) continue;
                    for (int i = 0; i < sz(res); i++) {
                        if (vec[i] != res[i]) ok = false;
                    }
                }
                if (ok) total_res.emplace_back(res), ans++;
            }
            for (int i = ind + 1; i < n; i++) {
                res.emplace_back(a[i]);
                self(self, i, sum + a[i], res);
                res.pop_back();
            }
        };
        vector<int> t;
        dfs(dfs, -1, 0, t);
        cout << ans << endl;
        return 0;
    }
    

\(\text{RegenSolution}\)

int main()
{
    int n;
    cin >> n;
    vector<int> a(n);
    for (auto& i : a) cin >> i;
    sort(all(a));
    int ans = 0;
    auto check = [&](int x) {
        if (x < 2) return false;
        for (int i = 2; i * i <= x; i++) if (x % i == 0) return false;
        return true;
    };
    auto dfs = [&](auto self, int now, int sum, bool flag)->void {
        if (now == n) {
            if (check(sum)) ans++;
            return ;
        }
        self(self, now + 1, sum, false);//该元素不选,或者前面重复过了,不能再选
        if (flag || a[now - 1] != a[now])//如果这个元素是不和上一个元素重复的,那么后面所有的方案都是唯一的,那么该元素可以选
            self(self, now + 1, sum + a[now], true);
    };
    sort(all(a));//先排好序,这样重复的元素相邻,方便处理
    dfs(dfs, 0, 0, true);
    cout << ans << endl;
    return 0;
}

充满希望的连通块问题

MySolution

我用的并查集,但这里雷根哥指出一个问题。

int findSet(int x) {return x == fa[x] ? x : (fa[x] = findSet(fa[x]));}

void merge(int x, int y) {
    int fx = findSet(x), fy = findSet(y);
    if (fx == fy) return ;
    if (siz[fx] > siz[fy]) swap(fx, fy);
    fa[fx] = fy;
    siz[fy] += siz[fx]; 
}

int main()
{
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1;

    for (int _ = 0; _ < m; _++) {
        int u, v; cin >> u >> v;
        merge(u, v);
    }

    int x, y;
    cin >> x >> y;
    if (findSet(x) == findSet(y))  
        cout << siz[findSet(x)] << endl;
    else
        cout << 0 << endl;
    return 0;
}

这里的按秩合并是没有作用的

if (siz[fx] > siz[fy]) swap(fx, fy);

因为我已经进行了路径压缩,查找成本已经到了 \(O(1)\)。

\(\text{RegenSolution}\)​

此题还可以直接DFS

int main()
{
    int n, m;
    cin >> n >> m;

    for (int _ = 0; _ < m; _++) {
        int u, v; cin >> u >> v;
        add_edge(u, v); add_edge(v, u);
    }

    int x, y, ans = 0;
    cin >> x >> y;

    vector<bool> vis(n + 1);

    auto dfs = [&](auto self, int u) -> void {
        if (vis[u]) return ;
        vis[u] = true;
        ans++;
        for (int i = head[u]; i; i = edge[i].next) {
            self(self, edge[i].to);
        }
    };

    dfs(dfs, x);

    if (vis[y])  
        cout << ans << endl;
    else
        cout << 0 << endl;
    return 0;
}

充满希望的课程安排

T246212 充满希望的课程安排 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

用拓扑排序判环。

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#define inf 0x7fffffff
#define linf 0x7fffffffffffffff
#define endl '\n'
#define sz(X) (int)(X).size()
#define all1(X) (X).begin() + 1, (X).end()
#define all(X) (X).begin(), (X).end()

#define YES cout << "YES" << '\n'
#define Yes cout << "Yes" << '\n'
#define NO cout << "NO" << '\n'
#define No cout << "No" << '\n'
#define error cout << "-1" << '\n'
#define debug1(X) cout << #X << ": " << X << '\n'
#define debug2(X) cout << #X << ": " << X << ' '

using namespace std;
using ll = long long;

constexpr int N = 1e5 + 10;

struct Edge
{
    int to, next;
} edge[N << 1];

int head[N], tot;

void add_edge(int u, int v)
{
    edge[++tot].to = v, edge[tot].next = head[u];
    head[u] = tot;
}

int n, m, q[N << 1], d[N + 1];

int main()
{
    cin >> n >> m;
    for (int _ = 0, x, y; _ < m; _++)
    {
        cin >> x >> y;
        add_edge(x, y);
        d[y]++;
    }

    int cnt = 0;
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (d[i] == 0) q.push(i), cnt++;//先加入入度为0的点
    }

    while(!q.empty()) {//拓扑排序
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = edge[i].next) {
            int to = edge[i].to;
            d[to]--;
            if (d[to] == 0) q.push(to), cnt++;
        }
    }
    
    if (cnt == n) YES;//所有点成拓扑序
    else NO;

}

标签:int,auto,self,cin,dfs,RegenDay01,sum
From: https://www.cnblogs.com/kdlyh/p/18011124

相关文章