ECNU 3462 最小 OR 路径 (贪心 + 并查集)
题目链接 EOJ Monthly 2018.1 Problem F
先假设答案的每一位都是$1$,然后从高位开始,选出那些该位置上为$0$的所有边,并查集判断连通性。
如果$s$和$t$可以连通的话,那么该位置$0$,然后用刚刚选出来的这些边再继续做下去。
如果$s$和$t$不连通的话,那么不做任何操作,继续处理低位。
这样就可以保证答案一定是最小的。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
const int N = 1e4 + 10;
const int M = 1e6 + 10;
struct node{
int x, y;
LL z;
void scan(){ scanf("%d%d%lld", &x, &y, &z);}
} e[M];
int n, m, s, t;
int x;
int father[N];
vector <node> f[2];
LL ans;
int getfather(int x){
return father[x] ? father[x] = getfather(father[x]) : x;
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, m) e[i].scan();
scanf("%d%d", &s, &t);
ans = (1ll << 62) - 1;
rep(i, 1, m){
int x = e[i].x, y = e[i].y;
int fx = getfather(x), fy = getfather(y);
if (fx ^ fy){
father[fx] = fy;
}
}
if (getfather(s) != getfather(t)) return 0 * puts("-1");
x = 0;
rep(i, 1, m) f[0].push_back(e[i]);
dec(i, 61, 0){
memset(father, 0, sizeof father);
f[x ^ 1].clear();
for (auto edge : f[x]){
LL val = edge.z;
if (!((1ll << i) & val)){
f[x ^ 1].push_back(edge);
}
}
for (auto edge : f[x ^ 1]){
int x = edge.x, y = edge.y;
int fx = getfather(x), fy = getfather(y);
if (fx ^ fy) father[fx] = fy;
}
int fs = getfather(s), ft = getfather(t);
if (fs == ft){
ans ^= (1ll << i);
x ^= 1;
}
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号