EOJ Monthly 2018.1 F 最小OR路径

Posted 救命怀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

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

Hard

\\(2\\le 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\\n", 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\\n", ans);
    return 0;
}

以上是关于EOJ Monthly 2018.1 F 最小OR路径的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别