• EOJ Monthly 2018.1 F 最小OR路径


    题目链接

    Description

    给定一个有 (n) 个点和 (m) 条边的无向图,其中每一条边 (e_i) 都有一个权值记为 (w_i)

    对于给出的两个点 (a)(b) ,求一条 (a)(b) 的路径,使得路径上的边权的 (OR)(位或)和最小,输出这个值。(也就是说,如果将路径看做边的集合 ({e_1,e_2,…,e_k}),那么这条路径的代价为 (w_1 OR w_2 OR … OR w_k),现在求一条路径使得其代价最小,输出这个代价。如果不存在这样的路径,输出 (-1)

    Input

    Easy

    (2le n le 10^4, 0 le m le 10^6, 0 le c_i le 2^{62}-1)

    Hard

    (2le n le 10^4, 0 le m le 10^6, 0 le c_i le 2^{62}-1)

    题解 By zerol

    Easy

    (dp[u][k]) 表示到结点 (u) 的代价为 (k) 的方案是否存在,然后在图上转移(dfs 一下就好了)。

    Hard

    假设答案的二进制位全是 (1),然后从高位到低位考虑,如果将该位置为 (0) 不破坏连通性的话就置为 (0),这样肯定最优。
    判断连通性可以用 并查集 或者 搜索,反正 (O(M)) 就行。
    复杂度 (O(63M))

    对比

    稍微回顾一下之前的 bzoj 2115 [Wc2011] Xor 路径最大异或和 线性基

    共同点:从高位向低位做,判断当前位能否置为1或0(毕竟都是位运算)

    不同点:
    Xor那道题是预处理出来一条路径,以及所有可以补充于其上的路径。所以,判断能否置为1即是看能否添加这条路径。
    而这道题,因为OR运算的性质,直观想来,添加的路径越少OR和就越小。所以,判断当前位能否置为0即是通过连通性来判断。

    Code

    Easy

    #include <bits/stdc++.h>
    #define maxn 1100
    #define maxm 10010
    using namespace std;
    bool vis[maxn][maxn];
    struct Edge { int to, ne, w; } edge[maxm << 1];
    int tot, ne[maxn];
    void add(int u, int v, int w) {
        edge[tot] = {v, ne[u], w};
        ne[u] = tot++;
    }
    typedef long long LL;
    void dfs(int u, int ors) {
        if (vis[u][ors]) return;
        vis[u][ors] = true;
        for (int i = ne[u]; ~i; i = edge[i].ne) {
            int v = edge[i].to;
            dfs(v, ors | edge[i].w);
        }
    }
    int main() {
        memset(ne, -1, sizeof ne);
        int n, m;
        scanf("%d%d", &n,&m);
        int u, v, w;
        for (int i = 0; i < m; ++i) {
            scanf("%d%d%d", &u,&v,&w);
            add(u,v,w); add(v, u, w);
        }
        scanf("%d%d", &u, &v);
        dfs(u, 0);
        for (int i = 0; i <= 1024; ++i) {
            if (vis[v][i]) { printf("%d
    ", i); return 0; }
        }
        puts("-1");
        return 0;
    }
    
    

    Hard

    #include <bits/stdc++.h>
    #define maxn 10010
    #define maxm 1000010
    using namespace std;
    typedef long long LL;
    vector<int> a[maxn];
    struct Edge { int u, v; } edge[maxm];
    void add(LL w, int id) {
        int cnt = 0;
        while (w) {
            if (w & 1) a[cnt].push_back(id);
            w >>= 1, ++cnt;
        }
    }
    int s, t, n, m, fa[maxn], sz[maxn];
    bool exc[maxm], flag[64];
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    void unionn(int u, int v) {
        u = find(u), v = find(v);
        if (sz[u] < sz[v]) swap(u, v);
        sz[u] += sz[v], fa[v] = u;
    }
    bool ok(int id) {
        memset(exc, 0, sizeof exc);
        for (int i = 62; i >= id; --i) {
            if (!flag[i]) {
                for (auto x : a[i]) exc[x] = true;
            }
        }
        for (int i = 1; i <= n; ++i) fa[i] = i, sz[i] = 1;
        for (int i = 0; i < m; ++i) {
            if (!exc[i]) unionn(edge[i].u, edge[i].v);
        }
        return find(s) == find(t);
    }
    int main() {
        scanf("%d%d", &n,&m);
        for (int i = 0; i < m; ++i) {
            int u, v; LL w;
            scanf("%d%d%lld", &u,&v,&w);
            edge[i] = {u, v};
            add(w, i);
        }
        scanf("%d%d", &s, &t);
        if (!ok(64)) { puts("-1"); return 0; }
        LL ans = 0;
        for (int i = 62; i >= 0; --i) {
            ans <<= 1;
            if (!ok(i)) flag[i] = 1, ans |= 1;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    小组项目进度汇报
    小组项目进程展示
    结队项目
    小组计划
    个人项目:数独
    问题
    自我介绍
    结对项目
    软件工程基础大项目——数独问题
    关于软件工程的几个问题
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/8358715.html
Copyright © 2020-2023  润新知